[2018 ICPC 沈阳 E] The Kouga Ninja Scrolls

https://codeforces.ml/gym/101955/problem/E
题意:
给你\(n\)个忍者在二维平面的坐标和他们的所属团队,每次可以增加忍者的坐标值、修改忍者所在团队,或者询问\(l\) ~ \(r\)号忍者中,不在同一个团队的两个忍者之间的最长曼哈顿距离。

思路:
区间查询,试试往线段树靠。曼哈顿距离并不好维护,所以转换成切比雪夫距离,维护\(x\)和\(y\)上的的最大值和最小值。如果没有所属团队的限制条件,我们将\(x\)轴上的最大最小值的差值和\(y\)上的进行比较,输出较大的就行。在不能所属同一个团队的限制条件下,我们在记录最大值的同时,记录一个次大值(非严格小于最大值),并且保证最大值和次大值所属不同的团队,最小值同理。这样一来,如果发现最大值和最小值的团队相同,就可以用最大值减去次小值,次大值减去最小值去比较,并且在线段树中也是可以进行维护的。

#include <bits/stdc++.h>

using namespace std;
#define ls (id << 1)
#define rs (id << 1 | 1)
#define mid (l + r >> 1)
inline int rd() {
    int f = 0; int x = 0; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) f |= (ch == '-');
    for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    if (f) x = -x;
    return x;
}

typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 7;

ll a[2][N];
int c[N];
int n;

struct Seg{
    struct node{
        ll mx, mmx;
        int mxid;
        ll mi, mii;
        int miid;
    }t[N << 2];

    node merge(node ln, node rn) {
        node tmp = ln;
        if (rn.mxid != tmp.mxid) {
            if (rn.mx > tmp.mx) {
                tmp.mmx = max(tmp.mx, rn.mmx);
                tmp.mx = rn.mx;
                tmp.mxid = rn.mxid;
            } else {
                tmp.mmx = max(tmp.mmx, rn.mx);
            }
        } else {
            if (rn.mx > tmp.mx) {
                tmp.mx = rn.mx;
                tmp.mxid = rn.mxid;
            }
            tmp.mmx = max(tmp.mmx, rn.mmx);
        }

        if (rn.miid != tmp.miid) {
            if (rn.mi < tmp.mi) {
                tmp.mii = min(tmp.mi, rn.mii);
                tmp.mi = rn.mi;
                tmp.miid = rn.miid;
            } else {
                tmp.mii = min(tmp.mii, rn.mi);
            }
        } else {
            if (rn.mi < tmp.mi) {
                tmp.mi = rn.mi;
                tmp.miid = rn.miid;
            }
            tmp.mii = min(tmp.mii, rn.mii);
        }
        return tmp;
    }

    void up(int id) {
        t[id] = merge(t[ls], t[rs]);
    }
    
    void build(int id, int l, int r, int tp) {
        
        if (l == r) {
            t[id].mx = t[id].mi = a[tp][l];
            t[id].mxid = t[id].miid = c[l];
            t[id].mmx = -INF;
            t[id].mii = INF;
            return;
        }
        build(ls, l, mid, tp);
        build(rs, mid + 1, r, tp);
        up(id);
    }
    
    void modify(int id, int l, int r, int p, int tp) {
        if (l == r) {
            t[id].mx = t[id].mi = a[tp][l];
            t[id].mxid = t[id].miid = c[l];
            return;
        }
        if (p <= mid) modify(ls, l, mid, p, tp);
        else modify(rs, mid + 1, r, p, tp);
        up(id);
    }

    node query(int id, int l, int r, int ql, int qr) {
        if (l >= ql && r <= qr) return t[id];
        int flag = 0;
        node tmp;
        if (ql <= mid) {
            flag = 1;
            tmp = query(ls, l, mid, ql, qr);
        }
        if (qr > mid) {
            if (!flag) tmp = query(rs, mid + 1, r, ql, qr);
            else tmp = merge(tmp, query(rs, mid + 1, r, ql, qr));
        }
        return tmp;
    }

    ll getMax(int ql, int qr) {
        node tmp = query(1, 1, n, ql, qr);
        if (tmp.mxid != tmp.miid) {
            return tmp.mx - tmp.mi;
        }
        if (tmp.mii == INF && tmp.mmx == -INF) return 0;
        return max(tmp.mx - tmp.mii, tmp.mmx - tmp.mi);
    }
}seg[2];

ll x[N], y[N];
int cas;

void solve() {
    printf("Case #%d:\n", ++cas);
    n = rd();
    int q = rd();
    for (int i = 1; i <= n; ++i) {
        x[i] = rd(), y[i] = rd();
        a[0][i] = x[i] + y[i];
        a[1][i] = x[i] - y[i];
        c[i] = rd();
    }
    seg[0].build(1, 1, n, 0);
    seg[1].build(1, 1, n, 1);
    while (q--) {
        int op = rd();
        if (op == 1) {
            int i = rd();
            ll xi = rd(), yi = rd();
            x[i] += (ll)xi;
            y[i] += (ll)yi;
            a[0][i] = x[i] + y[i];
            a[1][i] = x[i] - y[i];
            seg[0].modify(1, 1, n, i, 0);
            seg[1].modify(1, 1, n, i, 1);
        } else if (op == 2) {
            int i = rd();
            c[i] = rd();
            seg[0].modify(1, 1, n, i, 0);
            seg[1].modify(1, 1, n, i, 1);
        } else {
            int ql = rd();
            int qr = rd();
            printf("%lld\n", max(seg[0].getMax(ql, qr), seg[1].getMax(ql, qr)));
        }
    }
}

int main() {
    int t = 1;
    t = rd();
    while (t--) solve();
    return 0;
}
上一篇:RN开发日常记录


下一篇:android设计模式总结,字节跳动算法工程师面试总结