题目:https://codeforces.com/contest/1093/problem/G
题目是区间最大两点间曼哈顿距离,在线,空间是k维的,但是k最大只有5。
因为k比较小,所以可以用曼哈顿距离的经典做法,用二进制来枚举。
呃,32颗线段树。
ac代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
const int maxk = 5;
const int inf = 1e9 + 7;
int n, k, m;
int t[maxn << 2][35];
int in[maxk];
int res[35];
void get(int rt) {
for(int i = 0; i < k; i++) {
scanf("%d", &in[i]);
}
for(int i = 0; i < m; i++) {
t[rt][i] = 0;
for(int j = 0; j < k; j++) {
if((i >> j) & 1) {
t[rt][i] += in[j];
} else {
t[rt][i] -= in[j];
}
}
}
}
void merge(int rt) {
for(int i = 0; i < m; i++) {
res[i] = max(res[i], t[rt][i]);
}
}
void pushUp(int rt) {
int l = rt << 1, r = rt << 1 | 1;
for(int i = 0; i < m; i++) {
t[rt][i] = max(t[l][i], t[r][i]);
}
}
void build(int rt, int l, int r) {
if(l == r) {
get(rt);
return;
}
int mid = (l + r) >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
pushUp(rt);
}
void update(int rt, int l, int r, int pos) {
if(l == r) {
get(rt);
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) {
update(rt << 1, l, mid, pos);
} else {
update(rt << 1 | 1, mid + 1, r, pos);
}
pushUp(rt);
}
void query(int rt, int l, int r, int L, int R) {
if(l >= L && r <= R) {
merge(rt);
return;
}
int mid = (l + r) >> 1;
if(L <= mid) {
query(rt << 1, l, mid, L, R);
}
if(R > mid) {
query(rt << 1 | 1, mid + 1, r, L, R);
}
}
int main() {
scanf("%d%d", &n, &k);
m = 1 << k;
build(1, 1, n);
int q, op, l, r;
scanf("%d", &q);
while(q--) {
scanf("%d", &op);
if(op == 1) {
scanf("%d", &l);
update(1, 1, n, l);
} else {
scanf("%d%d", &l, &r);
for(int i = 0; i < m; i++) {
res[i] = -inf;
}
query(1, 1, n, l, r);
int ans = -inf;
for(int i = 0; i < m; i++) {
ans = max(ans, res[i] + res[i ^ (m - 1)]);
}
printf("%d\n", ans);
}
}
return 0;
}