类似套路, 将绝对值拆开
我们设置一个状态S, 如果第i为是1, 就加上a[i], 否则为-a[i]
那么一个合法的组合就是 val[S] + val[31-S], 于是在线段树中选两个最大的点加起来更新答案就可以了
#include<bits/stdc++.h>
#define N 200050
using namespace std;
const int inf = 0x3fffffff;
int read(){ int x; scanf("%d", &x); return x;}
struct Node{ int Max[32];} t[N<<2];
int n, k, m, a[N][5];
Node Init(int *A){ Node ans;
for(int S=0; S<(1<<k); S++){ int sum = 0;
for(int j=0; j<k; j++){ if(S & (1<<j)) sum += A[j]; else sum -= A[j];}
ans.Max[S] = sum;
} return ans;
}
void Pushup(int x){
for(int i=0; i<(1<<k); i++){
t[x].Max[i] = max(t[x<<1].Max[i], t[x<<1|1].Max[i]);
}
}
void Build(int x, int l, int r){
for(int i=0; i<(1<<k); i++) t[x].Max[i] = -inf;
if(l == r){ t[x] = Init(a[l]); return;}
int mid = (l+r) >> 1;
Build(x<<1, l, mid); Build(x<<1|1, mid+1, r);
Pushup(x);
}
void Modify(int x, int l, int r, int pos){
if(l == r){ t[x] = Init(a[l]); return;}
int mid = (l+r) >> 1;
if(pos <= mid) Modify(x<<1, l, mid, pos);
else Modify(x<<1|1, mid+1, r, pos);
Pushup(x);
}
int Quary(int S, int x, int l, int r, int L, int R){
if(L<=l && r<=R) return t[x].Max[S];
int mid = (l+r) >> 1, ans = -inf;
if(L<=mid) ans = max(ans, Quary(S, x<<1, l, mid, L, R));
if(R>mid) ans = max(ans, Quary(S, x<<1|1, mid+1, r, L, R));
return ans;
}
int main(){
n = read(); k = read();
for(int i=1; i<=n; i++){
for(int j=0; j<k; j++) a[i][j] = read();
} Build(1, 1, n);
m = read();
while(m--){
int op = read();
if(op == 1){
int pos = read();
for(int i=0; i<k; i++) a[pos][i] = read();
Modify(1, 1, n, pos);
}
if(op == 2){
int l = read(), r = read(), ans = 0;
for(int S = 0; S < (1<<k); S++){
ans = max(ans, Quary(S, 1, 1, n, l, r) + Quary((1<<k) - S - 1, 1, 1, n, l, r));
} printf("%d\n", ans);
}
} return 0;
}