Codeforces Educational Codeforces Round 56 (Rated for Div. 2) 1093G. Multidimensional Queries

有一 k k k维点序列。
[ l , r ] [l,r] [l,r]之间 Manhattan \text{Manhattan} Manhattan距离最大的点。要求点修改区间查询。
解:每维的坐标分解如下:
∣ a j − b j ∣ = a j − b j   o r   b j − a j , j = 1 , 2 , . . . , k |a_{j}-b_j|=a_{j}-b_{j}\ or\ b_{j}-a_{j},j=1,2,...,k ajbj=ajbj or bjaj,j=1,2,...,k
因此一个点的 Manhattan \text{Manhattan} Manhattan 2 k 2^k 2k种情况控制。
假设 M i ( a , b ) M_i(a,b) Mi(a,b)代表其中的第 i i i种情况, M ( a , b ) M(a,b) M(a,b)代表 a , b a,b a,b Manhattan \text{Manhattan} Manhattan距离。可以证明:
M ( a , b ) = max ⁡ i = 1 2 k { M i ( a , b ) } M(a,b)=\max_{i=1}^{2^k}\{M_i(a,b)\} M(a,b)=i=1max2k{Mi(a,b)}
所以:
res = max ⁡ a , b ∈ a [ l , r ] M ( a , b ) = max ⁡ a , b ∈ a [ l , r ] max ⁡ i = 1 2 k { M i ( a , b ) } = max ⁡ i = 1 2 k max ⁡ a , b ∈ a [ l , r ] { M i ( a , b ) } \text{res}=\max_{a,b\in a[l,r]} M(a,b)=\max_{a,b\in a[l,r]} \max_{i=1}^{2^k}\{M_i(a,b)\}= \max_{i=1}^{2^k}\max_{a,b\in a[l,r]}\{M_i(a,b)\} res=a,ba[l,r]maxM(a,b)=a,ba[l,r]maxi=1max2k{Mi(a,b)}=i=1max2ka,ba[l,r]max{Mi(a,b)}
显然 max ⁡ a , b ∈ a [ l , r ] { M i ( a , b ) } \displaystyle \max_{a,b\in a[l,r]}\{M_i(a,b)\} a,ba[l,r]max{Mi(a,b)}可以通过线段树维护。因此总的时间复杂度为 O ( 2 k n lg ⁡ n ) \mathrm{O}(2^kn\lg n) O(2knlgn)

#include 
#include 
#include 
#include 
using namespace std;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char GET_CHAR(){
	if(head==tail){
		int l=fread(buffer,1,BufferSize,stdin);
		tail=(head=buffer)+l;
		if(head==tail)return EOF;
	}
	return *head++;
}
inline int READ(){
	int x=0,f=1;char c=GET_CHAR();
	for(;!isdigit(c);c=GET_CHAR()){
		if(c==EOF)return EOF;
		if(c=='-')f=-1;
	}
	for(;isdigit(c);c=GET_CHAR())x=(((x<<2)+x)<<1)+c-'0';
	return x*f;
}
const int N=200005;
int sgs[N<<2][32],sgt[N<<2][32];
int a[N][6];int k,kk;
int rl[32],rr[32];
void build(int p,int l,int r){
	if(l==r){
		int res;
		for(int i=0;i<kk;i++){
			res=0;
			for(int j=0;j<k;j++){
				if((i>>j)&1){
					res+=a[l][j];
				}else{
					res-=a[l][j];
				}
			}
			sgs[p][i]=sgt[p][i]=res;
		}
		return ;
	}
	int m=(l+r)>>1;
	build(p<<1,l,m);
	build(p<<1|1,m+1,r);
	for(int i=0;i<kk;i++){
		sgs[p][i]=min(sgs[p<<1][i],sgs[p<<1|1][i]);
		sgt[p][i]=max(sgt[p<<1][i],sgt[p<<1|1][i]);
	}
}
void ck(int p,int l,int r){
	if(l==r)return ;
	int m=(l+r)>>1;
	ck(p<<1,l,m);ck(p<<1|1,m+1,r);
}
void update(int p,int l,int r,int x){
	if(l==r){
		int res;
		for(int i=0;i<kk;i++){
			res=0;
			for(int j=0;j<k;j++){
				if((i>>j)&1){
					res+=a[l][j];
				}else{
					res-=a[l][j];
				}
			}
			sgs[p][i]=sgt[p][i]=res;
		}
		return ;
	}
	int m=(l+r)>>1;
	if(x<=m)update(p<<1,l,m,x);
	else update(p<<1|1,m+1,r,x);
	for(int i=0;i<kk;i++){
		sgs[p][i]=min(sgs[p<<1][i],sgs[p<<1|1][i]);
		sgt[p][i]=max(sgt[p<<1][i],sgt[p<<1|1][i]);
	}
}
void query(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R){
		for(int i=0;i<kk;i++){
			rl[i]=min(sgs[p][i],rl[i]);
			rr[i]=max(sgt[p][i],rr[i]);
		}
		return ;
	}
	int m=(l+r)>>1;
	if(L<=m)query(p<<1,l,m,L,R);
	if(m< R)query(p<<1|1,m+1,r,L,R);
}
int main(){
	int n;
	n=READ();k=READ();
	kk=1<<k;
	for(int i=1;i<=n;i++){
		for(int j=0;j<k;j++){
			a[i][j]=READ();
		}
	}
	build(1,1,n);
	int q=0;
	q=READ();
	while(q--){
		int o;
		o=READ();
		if(o==1){
			int i;
			i=READ();
			for(int j=0;j<k;j++){
				a[i][j]=READ();
			}
			update(1,1,n,i);
		}else{
			int l,r;
			l=READ();r=READ();
			for(int i=0;i<kk;i++)rl[i]=0x3f3f3f3f,rr[i]=-0x3f3f3f3f;
			query(1,1,n,l,r);
			int res=0;
			for(int i=0;i<kk;i++){
				res=max(res,rr[i]-rl[i]);
			}
			printf("%d\n",res);
		}
		//ck(1,1,n);
	}
}

你可能感兴趣的:(codeforces,数学,线段树)