[CF1093G]Multidimensional Queries:线段树

分析

非常有趣的一道题。

式子中的绝对值很难处理,但是我们发现:

\[\sum_{i=1}^{k}|a_{x,i}-a_{y,i}|=\sum_{i=1}^{k}max(a_{x,i}-a_{y,i},a_{y,i}-a_{x,i})=max\{\sum_{i=1}^{k}c_ia_{x,i}-\sum_{i=1}^{k}c_ia_{y,i}\} \]

其中\(c\)是所有长度为\(k\)的只由\(-1\)\(1\)组成的数列,共有\(2^k\)种。

所以我们可以对于每一种\(c\)维护一棵支持单点修改,查询区间最小值和最大值的线段树,对所有的极差取\(max\)即可。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}

const int MAXN=200005;
int n,k,q,cnt,loc,ql,qr,xx[MAXN][6];
struct sgt{
	int maxn[33],minn[33];
}a[MAXN<<2],kk;

#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
inline sgt mer(sgt x,sgt y){
	rin(i,0,cnt-1) x.maxn[i]=std::max(x.maxn[i],y.maxn[i]),x.minn[i]=std::min(x.minn[i],y.minn[i]);
	return x;
}

void build(int o,int l,int r){
	if(l==r){
		rin(i,0,cnt-1){
			rin(j,0,k-1){
				if((i>>j)&1) a[o].maxn[i]+=xx[l][j];
				else a[o].maxn[i]-=xx[l][j];
			}
			a[o].minn[i]=a[o].maxn[i];
		}
		return;
	}
	build(lc,l,mid);build(rc,mid+1,r);
	a[o]=mer(a[lc],a[rc]);
}

void upd(int o,int l,int r){
	if(l==r){
		a[o]=kk;
		return;
	}
	if(loc<=mid) upd(lc,l,mid);
	else upd(rc,mid+1,r);
	a[o]=mer(a[lc],a[rc]);
}

sgt query(int o,int l,int r){
	if(ql<=l&&r<=qr) return a[o];
	if(mid<ql) return query(rc,mid+1,r);
	else if(mid>=qr) return query(lc,l,mid);
	else return mer(query(lc,l,mid),query(rc,mid+1,r));
}
#undef mid
#undef lc
#undef rc

int main(){
	n=read(),k=read();cnt=(1<<k);
	rin(i,1,n) rin(j,0,k-1) xx[i][j]=read();
	build(1,1,n);
	q=read();
	while(q--){
		int opt=read();
		if(opt==1){
			loc=read();rin(i,0,k-1) xx[0][i]=read();
			rin(i,0,cnt-1){
				kk.maxn[i]=0;
				rin(j,0,k-1){
					if((i>>j)&1) kk.maxn[i]+=xx[0][j];
					else kk.maxn[i]-=xx[0][j];
				}
				kk.minn[i]=kk.maxn[i];
			}
			upd(1,1,n);
		}
		else{
			ql=read(),qr=read();
			sgt Ans=query(1,1,n);int ans=0;
			rin(i,0,cnt-1) ans=std::max(ans,Ans.maxn[i]-Ans.minn[i]);
			printf("%d\n",ans);
		}
	}
	return 0;
}

posted on 2018-12-20 19:43  ErkkiErkko  阅读(155)  评论(2编辑  收藏

统计