Educational Codeforces Round 56 (Rated for Div. 2) G题(线段树,曼哈顿距离)

题目传送门
以二维为例,二维下两点间的曼哈顿距离最大值为\(max(|x_i-x_j| + |y_i-y_j|)\),可以通过枚举坐标符号正负来去掉绝对值。即\(max(x_i-x_j+y_i-y_j,x_i+x_j+y_i-y_j...)\)共16种情况。设\(f[i][t]\)表示第\(i\)个点各维度数值正负状态为\(t\)时的值,假如二维向量\(p[i]=(1,2)\),那么状态\(t\)的范围为\([0,3]\),如果\(t=2\),即二进制表示为\(10\),那么\(p\)向量第一维数值加个负号,第二维数值不变,类似状压过程。对于每个向量处理出\(f\)的值。最终结果即在\([l,r]\)范围内求\(max(f[i][m],f[j][n])(m+n=(1<<k)-1)\),具体用线段树实现。

#include<cstdio>
#include<vector>
#include<algorithm>
#define ls (u << 1)
#define rs (u << 1 | 1)
using namespace std;
const int N = 2e5 + 50;

struct Node{
    vector<int> val;
    Node() { val.resize(35); }
}node[N << 2];

int n, k, q;
int a[N][6];

void Max(const vector<int> &x, const vector<int> &y, vector<int> &z){
    for(int i = 0; i < (1 << k); ++i)  z[i] = max(x[i], y[i]);
}

void Max(const vector<int> &x, vector<int> &y){
    for(int i = 0; i < (1 << k); ++i)  y[i] = max(x[i], y[i]);
}

void build(int u, int l, int r){
    if(l == r){
        for(int s = 0; s < (1 << k); ++s){
            for(int t = 1; t <= k; ++t){
                if(s & (1 << (t - 1)))  node[u].val[s] += a[l][t];
                else  node[u].val[s] -= a[l][t];
            }
        }
        return ;
    }
    int mid = (l + r) >> 1;
    if(l <= mid)  build(ls, l, mid);
    if(r > mid)  build(rs, mid + 1, r);
    Max(node[ls].val, node[rs].val, node[u].val);
}

void modify(int u, int l, int r, int pos){
    if(l == r){
    	for(int i = 0; i < (1 << k); ++i)   node[u].val[i] = 0;
        for(int s = 0; s < (1 << k); ++s){
            for(int t = 1; t <= k; ++t){
                if(s & (1 << (t - 1)))  node[u].val[s] += a[l][t];
                else  node[u].val[s] -= a[l][t];
            }
        }
        return ;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid)  modify(ls, l, mid, pos);
    else  modify(rs, mid + 1, r, pos);
    Max(node[ls].val, node[rs].val, node[u].val);
}

vector<int> ans(35);

void query(int u, int l, int r, int ql, int qr){
	if(ql <= l && qr >= r){
        Max(node[u].val, ans);
        return ;        
    }
    int mid = (l + r) >> 1;
    if(ql <= mid)  query(ls, l, mid, ql, qr);
    if(qr > mid)  query(rs, mid + 1, r, ql, qr);
}

int main(){
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; ++i)
        for(int t = 1; t <= k; ++t)
            scanf("%d", &a[i][t]);
    build(1, 1, n);
    scanf("%d", &q);
    while(q--){
        int opt, id, l, r;
        scanf("%d", &opt);
        if(opt == 1){
            scanf("%d", &id);
            for(int i = 1; i <= k; ++i)  scanf("%d", &a[id][i]);
            modify(1, 1, n, id);
        }
        else{
            for(int i = 0; i < 35; ++i)  ans[i] = -1e9;
            scanf("%d%d", &l, &r);
            query(1, 1, n, l, r);
            int maxx = 0;
            for(int s = 0; s < (1 << k); ++s){
                maxx = max(maxx, ans[s] + ans[(1 << k) - 1 - s]);
            }
            printf("%d\n", maxx);  
        }
    }
}
posted @ 2021-01-14 18:19  のNice  阅读(65)  评论(0编辑  收藏  举报