题目:洛谷P4390、BZOJ1176。
题目大意:
给你一个(W imes W)的矩阵,初始每个数都为(S)。现在有若干操作:
1. 给某个格子加上一个值;
2. 询问某个子矩阵的值的和;
3. 结束询问
解题思路:
CDQ分治。
离线操作,把询问拆成4个矩阵(二维前缀和)。
对(x)轴排序,分治询问,用左区间的修改来更新右区间的询问。由于(x)已被排序,我们直接用树状数组维护(y)的前缀和即可。
也可以边CDQ边归并排序。
时间复杂度(O(nlog^2 n))。
C++ Code:
#include<cstdio> #include<algorithm> #include<cctype> #define LoveLive long long #define M 2000005 int S,W,cnt=0; LoveLive bit[M]; inline int readint(){ int c=getchar(),d=0,f=0; for(;!isdigit(c);c=getchar())f=c=='-'; for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return f?-d:d; } struct Qs{ int type,x,y,id;LoveLive num;//type 0: modify; type 1: query. inline bool operator<(const Qs&rhs)const{return id<rhs.id;} }q[200020],t[200020]; inline void add(int x,LoveLive y){for(int i=x;i<M;i+=i&-i)bit[i]+=y;} inline LoveLive ask(int x){LoveLive ans=0;for(int i=x;i;i-=i&-i)ans+=bit[i];return ans;} inline void clear(int x){for(int i=x;i<M;i+=i&-i)bit[i]=0;} void cdq(int l,int r){ if(l<r){ int mid=l+r>>1; cdq(l,mid),cdq(mid+1,r); int a=l,b=mid+1,c=l; while(a<=mid&&b<=r){ if(q[a].x<=q[b].x){ if(!q[a].type)add(q[a].y,q[a].num); t[c++]=q[a++]; }else{ if(q[b].type)q[b].num+=ask(q[b].y); t[c++]=q[b++]; } } while(a<=mid){ if(!q[a].type)add(q[a].y,q[a].num); t[c++]=q[a++]; } while(b<=r){ if(q[b].type)q[b].num+=ask(q[b].y); t[c++]=q[b++]; } for(int i=l;i<=mid;++i)if(!q[i].type)clear(q[i].y); for(int i=l;i<=r;++i)q[i]=t[i]; } } int main(){ S=readint(),W=readint(); for(int opt=readint();opt^3;opt=readint()){ if(opt==1){ int x=readint(),y=readint(),p=readint(); ++cnt; q[cnt]=(Qs){0,x,y,cnt,p}; }else{ int x1=readint(),y1=readint(),x2=readint(),y2=readint(); ++cnt;q[cnt]=(Qs){1,x1-1,y1-1,cnt,0}; ++cnt;q[cnt]=(Qs){1,x1-1,y2,cnt,0}; ++cnt;q[cnt]=(Qs){1,x2,y1-1,cnt,0}; ++cnt;q[cnt]=(Qs){1,x2,y2,cnt,0}; } } cdq(1,cnt); std::sort(q+1,q+cnt+1); for(int i=1;i<=cnt;++i) if(q[i].type){ printf("%d ",int(q[i+3].num-q[i+2].num-q[i+1].num+q[i].num+1ll*S*(q[i+3].y-q[i].y)*(q[i+3].x-q[i].x)));i+=3; } return 0; }