bzoj2683: 简单题
题目大意:给你一个N*N(N<=500000)的矩阵,支持单点修改,询问子矩阵的和。
思路:CDQ分治的第一题。前半部分和后半部分分别递归处理,然后处理前半部分的修改对后半部分询问的影响,这也是CDQ分治与一般的分治不同的地方。第一维排序,第二维用树状数组维护。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=500010,maxm=200010; int n,m,cnt,ans[maxm<<2],pos[maxm],op,x1,x2,y1,y2; struct Tdata{ int t,x,y,v,id; bool operator <(const Tdata &b)const{return x<b.x;} }que[maxm<<2]; struct Tbit{ int t[maxn]; void modify(int x,int v){for (int p=x;p<=n;p+=p&-p) t[p]+=v;} int query(int x){int res=0;for (int p=x;p;p-=p&-p) res+=t[p];return res;} }T; void cdq_solve(int l,int r){ if (l==r) return; int mid=(l+r)>>1; cdq_solve(l,mid),cdq_solve(mid+1,r); sort(que+l,que+1+mid),sort(que+mid+1,que+r+1); int i=l,j=mid+1,last=0; while (j<=r){ while (que[i].t==2&&i<=mid) ++i; while (que[j].t==1&&j<=r) ++j; if (i<=mid&&que[i].x<=que[j].x) T.modify(que[i].y,que[i].v),last=i++; else if (j<=r) ans[que[j].id]+=T.query(que[j].y),++j; } for (int i=l;i<=last;i++) if (que[i].t==1) T.modify(que[i].y,-que[i].v); } int main(){ scanf("%d",&n); for (;;){ scanf("%d",&op); if (op==1){ que[++m].t=op,que[m].id=m; scanf("%d%d%d",&que[m].x,&que[m].y,&que[m].v); } else if (op==2){ scanf("%d%d%d%d",&x1,&y1,&x2,&y2); pos[++cnt]=m; que[++m].t=op,que[m].id=m,que[m].x=x2,que[m].y=y2; que[++m].t=op,que[m].id=m,que[m].x=x1-1,que[m].y=y1-1; que[++m].t=op,que[m].id=m,que[m].x=x1-1,que[m].y=y2; que[++m].t=op,que[m].id=m,que[m].x=x2,que[m].y=y1-1; } else break; } cdq_solve(1,m); for (int i=1,p=pos[i];i<=cnt;i++,p=pos[i]) printf("%d\n",ans[p+1]+ans[p+2]-ans[p+3]-ans[p+4]); return 0; }