[2018 ICPC 瀋陽 E] The Kouga Ninja Scrolls
阿新 • • 發佈:2021-07-13
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; }