题意:给定N个K维的点,Q次操作,或者修改点的坐标;或者问[L,R]这些点中最远的点。
思路:因为最后一定可以表示维+/-(x1-x2)+/-(y1-y2)+/-(z1-z2).....
所以我们可以保存到线段树里,每次求区间最大值和最小值即可。
注意到我们可以先确定一个点的正负号,所以时间和空间节省了一半。
#include<bits/stdc++.h> #define mp make_pair #define pii pair<int,int> #define F first #define S second #define lson Now<<1 #define rson Now<<1|1 #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=800000; const int inf=1000000000; struct T { int Mx[maxn],Mn[maxn]; void update(int Now,int L,int R,int pos,int val) { if(L==R){ Mn[Now]=Mx[Now]=val; return ;} int Mid=(L+R)>>1; if(pos<=Mid) update(lson,L,Mid,pos,val); else update(rson,Mid+1,R,pos,val); Mx[Now]=max(Mx[lson],Mx[rson]); Mn[Now]=min(Mn[lson],Mn[rson]); } pii query(int Now,int L,int R,int l,int r) { if(l<=L&&r>=R) return mp(Mx[Now],Mn[Now]); int Mid=(L+R)>>1; int mx=-inf,mn=inf; pii tmp; if(l<=Mid){ tmp=query(lson,L,Mid,l,r); mx=max(mx,tmp.F); mn=min(mn,tmp.S); } if(r>Mid){ tmp=query(rson,Mid+1,R,l,r); mx=max(mx,tmp.F); mn=min(mn,tmp.S); } return mp(mx,mn); } }t[16]; int main() { int N,K,M,opt,L,R,p,x[6],KK; scanf("%d%d",&N,&K); KK=(1<<(K-1))-1; rep(i,0,KK){ rep(j,0,N*4) t[i].Mn[j]=inf,t[i].Mx[j]=-inf; } rep(i,1,N){ rep(j,0,K-1) scanf("%d",&x[j]); rep(j,0,KK) { int tmp=0; rep(k,0,K-1) if(j&(1<<k)) tmp+=x[k];else tmp-=x[k]; t[j].update(1,1,N,i,tmp); } } scanf("%d",&M); rep(i,1,M){ scanf("%d",&opt); if(opt==2){ scanf("%d%d",&L,&R); int ans=-inf; pii tmp; rep(j,0,KK){ pii tmp=t[j].query(1,1,N,L,R); ans=max(ans,tmp.F-tmp.S); ans=max(ans,tmp.S-tmp.F); } printf("%d ",ans); } else { scanf("%d",&p); rep(j,0,K-1) scanf("%d",&x[j]); rep(j,0,KK) { int tmp=0; rep(k,0,K-1) if(j&(1<<k)) tmp+=x[k];else tmp-=x[k]; t[j].update(1,1,N,p,tmp); } } } return 0; }