• CF1093G Multidimensional Queries


    \(\text{Solution}\)

    这玩意还有前置:\(P1648\) 看守
    自己竟然不会
    其实算比较套路的转化了

    先前置:必然是要把两点分开的
    所以绝对值要拆开,分维度考虑
    先看看两个二维点的曼哈顿距离
    \(dist(A,B) = \max(A_1-B_1,-A_1+B_1) + \max(A_2-B_2,-A_2+B_2)\)
    记为 \(dist(A,B) = \max(a_1,a_2) + \max(b_1,b_2) = \max(a_1+b_1,a_1+b_2,a_2+b_1,a_2+b_2)\)
    就是预测每个 \(\max\) 的结果组合起来
    这样的好处是————
    \(A,B\) 两点已经被分开啦
    观察 \(\max\) 里的任意一个式子
    其贡献是关于 \(A\) 每一维度的信息乘上一个系数再减去关于 \(B\) 每一维度的信息乘上一个相同的系数
    系数是对于每一维度要么 \(1\) 要么 \(-1\)
    这样不难想到怎么做了
    系数可以二进制枚举,相同系数下,可以维护 \(A\) 中每一维度的信息乘上一个系数的和的最大值
    相应的是 \(B\) 的最小值,当前系数下的答案就是两者相减了

    再看这道题,不就加了个单点修改吗?线段树维护即可

    \(\text{Code}\)

    #include <cstdio>
    #include <iostream>
    #define IN inline
    using namespace std;
    
    const int N = 2e5 + 5, INF = 0x3f3f3f3f;
    int n, d, a[N][5];
    
    IN void read(int &x) {
    	x = 0; char ch = getchar(); int f = 1;
    	for(; !isdigit(ch); f = (ch == '-' ? -1 : f), ch = getchar());
    	for(; isdigit(ch); x = (x<<3)+(x<<1)+(ch^48), ch = getchar());
    	x *= f;
    }
    
    struct node{
    	int a[33][2];
    	IN node() {for(int S = 0; S < (1 << d); S++) a[S][0] = -INF, a[S][1] = INF;}
    	IN void merge(node b) {
    		for(int S = 0; S < (1 << d); S++)
    			a[S][0] = max(a[S][0], b.a[S][0]), a[S][1] = min(a[S][1], b.a[S][1]);
    	}
    };
    	
    struct SegmentTree {
    	#define ls (p << 1)
    	#define rs (ls | 1)
    	
    	int Mx[N << 2][33], Mn[N << 2][33], tg[33][5];
    	IN void Init() {
    		for(int S = 0; S < (1 << d); S++)
    			for(int i = 0; i < d; i++) if ((S >> i) & 1) tg[S][i] = 1; else tg[S][i] = -1;
    	}
    	
    	IN void pushup(int p) {
    		for(int S = 0; S < (1 << d); S++)
    			Mx[p][S] = max(Mx[ls][S], Mx[rs][S]), Mn[p][S] = min(Mn[ls][S], Mn[rs][S]);
    	}
    	void build(int p, int l, int r) {
    		if (l == r) {
    			for(int S = 0; S < (1 << d); S++) {
    				Mx[p][S] = Mn[p][S] = 0;
    				for(int i = 0; i < 5; i++)
    					Mx[p][S] += tg[S][i] * a[l][i], Mn[p][S] += tg[S][i] * a[l][i];
    			}
    			return;
    		}
    		int mid = l + r >> 1;
    		build(ls, l, mid), build(rs, mid + 1, r), pushup(p);
    	}
    	
    	void Modify(int p, int l, int r, int x) {
    		if (l == r) {
    			for(int S = 0; S < (1 << d); S++) {
    				Mx[p][S] = Mn[p][S] = 0;
    				for(int i = 0; i < 5; i++)
    					Mx[p][S] += tg[S][i] * a[x][i], Mn[p][S] += tg[S][i] * a[x][i];
    			}
    			return;
    		}
    		int mid = l + r >> 1;
    		if (x <= mid) Modify(ls, l, mid, x);
    		else Modify(rs, mid + 1, r, x);
    		pushup(p);
    	}
    	node Query(int p, int l, int r, int x, int y) {
    		node res;
    		if (x <= l && r <= y) {
    			for(int S = 0; S < (1 << d); S++)
    				res.a[S][0] = max(res.a[S][0], Mx[p][S]), res.a[S][1] = min(res.a[S][1], Mn[p][S]);
    			return res;
    		}
    		int mid = l + r >> 1;
    		if (x <= mid) res = Query(ls, l, mid, x, y);
    		if (y > mid) res.merge(Query(rs, mid + 1, r, x, y));
    		return res;
    	}
    }T;
    
    int main() {
    	read(n), read(d);
    	for(int i = 1; i <= n; i++)
    		for(int j = 0; j < d; j++) read(a[i][j]);
    	int m;
    	T.Init(), T.build(1, 1, n), read(m);
    	for(int op, l, r; m; --m) {
    		read(op), read(l);
    		if (op == 1) {
    			for(int i = 0; i < d; i++) read(a[l][i]);
    			T.Modify(1, 1, n, l);
    		}
    		else {
    			read(r); int ans = 0; node k = T.Query(1, 1, n, l, r);
    			for(int S = 0; S < (1 << d); S++) ans = max(ans, k.a[S][0] - k.a[S][1]);
    			printf("%d\n", ans);
    		}
    	}
    }
    
  • 相关阅读:
    java 常用第3方工具
    反射与内省
    UDP通讯协议实例
    多线程及线程并发库Executors
    Deque 双端队列 Stack 堆栈
    Collections工具类
    Map 接口
    PHP控制电脑重启 关机
    ThinkPHP框架研究之一 基本函数 M和D的区别
    textarea输入输出的处理
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/16479607.html
Copyright © 2020-2023  润新知