这题妙啊。
学会了一个新\(trick\)。
题解
\[|x_1 - x_2|+|y_1 - y_2| = \\ max (x_1-x_2+y_1-y_2,x_1-x_2-y_1+y_2,-x_1+x_2+y_1-y2,-x_1+x_2-y_1+y_2) = \\max((x_1+y_1)-(x_2+y_2),(x_1-y_1)-(x_2-y_2),(-x_1+x_2)-(-y_1+y_2),(-x_1-y_1)-(-x_2-y_2)) \]
得到两个信息。
- 两个点的曼哈顿距离\(|x_1-x_2|+|y_1-y_2|+|z_1-z_2|+\dots = \sum^{...}_{x,y,z...}max(x_1-x_2,x_2-x_1)\)
- 当\(x_1\)前为\(+\)号,\(x_2\)前必定是\(-\)号。
由于这个题目里\(k <= 5\),可以枚举每一个点的\(x,y,z\dots\)坐标给答案贡献时前面的符号,可以用二进制来状压。那么对应的,另一个取得的点的状态就是这个点取反。(由第二个性质知道)。所以对每个点分别维护\(2^k\)个状态下的数值和,用线段树维护即可。最后的答案就是把询问区间的状态取出来,枚举每个状态下最大和再加上它取反的状态下最大和就是最大的答案了。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define R register
#define LL long long
const int inf = 0x3f3f3f3f;
const int MAXN = 2e5 + 10;
inline int read() {
char a = getchar(); int x = 0,f = 1;
for(; a > '9' || a < '0'; a = getchar()) if(a == '-') f = -1;
for(; a >= '0' && a <= '9' ;a = getchar()) x = x * 10 + a - '0';
return x * f;
}
int n, k;
int a[MAXN][5];
int mx[MAXN << 2][32];
struct Node {
Node() { memset(s, 0, sizeof(s)); }
int s[32];
};
inline int ls(int x) { return x << 1; }
inline int rs(int x) { return x << 1 | 1; }
inline void update(int x) {
for(R int S = (1 << k) - 1; S >= 0 ; S --) mx[x][S] = max(mx[ls(x)][S], mx[rs(x)][S]);
}
inline void build(int x, int l, int r) {
if(l == r) {
for(R int S = (1 << k) - 1; S >= 0 ; S --) {
mx[x][S] = 0;
for(R int i = 0; i < k; i ++)
if((1 << i) & S) mx[x][S] += a[l][i];
else mx[x][S] -= a[l][i];
}
return ;
}
int mid = l + r; mid >>= 1;
build(ls(x), l, mid); build(rs(x), mid + 1, r);
update(x);
}
int st[5];
inline void modify(int x, int l, int r, int ad) {
if(l == r) {
for(R int i = 0; i < k; i ++) st[i] = read();
for(R int S = (1 << k) - 1; S >= 0 ; S --) {
mx[x][S] = 0;
for(R int i = 0; i < k; i ++)
if((1 << i) & S) mx[x][S] += st[i];
else mx[x][S] -= st[i];
}
return ;
}
int mid = l + r; mid >>= 1;
if(ad <= mid) modify(ls(x), l, mid, ad);
else modify(rs(x), mid + 1, r, ad);
update(x);
}
inline Node ask(int x, int l, int r, int Le, int Ri) {
if( Le <= l && r <= Ri ) {
Node ans;
for(R int S = (1 << k) - 1; S >= 0 ; S --) {
ans.s[S]= mx[x][S];
}
return ans;
}
int mid = l + r; mid >>= 1;
/*if(Le <= mid) ans = max(ans, ask(ls(x), l, mid, Le, Ri));
if(Ri > mid) ans = max(ans, ask(rs(x), mid + 1, r, Le, Ri));*/
if(Ri <= mid) return ask(ls(x), l, mid, Le, Ri);
if(Le > mid) return ask(rs(x), mid + 1, r, Le, Ri);
Node la = ask(ls(x), l, mid, Le, Ri);
Node ra = ask(rs(x), mid + 1, r, Le, Ri);
for(R int S = ( 1 << k ) - 1; S >= 0; S --) {
la. s[S] = max(la. s[S], ra. s[S]);
}
return la;
}
int main() {
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
n = read(); k = read();
for(R int i = 1; i <= n; i ++) {
for(R int j = 0; j < k; j ++)
a[i][j] = read();
}
build(1, 1, n);
int q = read();
while(q --) {
if(read() == 1) {
int i = read();
modify(1, 1, n, i);
}
else {
int l = read(), r = read();
Node ans = ask(1, 1, n, l, r);
int res = 0;
for(R int S = ( 1 << k ) - 1; S >= 0; S --)
res = max( res, ans.s[S] + ans.s[((1 << k) - 1) ^ S]);
printf("%d\n",res);
}
}
return 0;
}