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;
}