Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 15849 | Accepted: 7321 |
Description
Input
Output
Sample Input
0 4 1 1 2 3 2 0 0 2 2 1 1 1 2 1 1 2 -1 2 1 1 2 3 3
Sample Output
3 4
操作0:S*S的矩阵置0 ,操作1:坐标(x,y)加v,操作2:[L,R],[B,T]这个矩阵的和。
一开始没看清楚题,以为操作1也是在矩阵内加,准备写个带pushdown二维线段树。但是写pushdown的时候发现写不出来,感觉好像有一维要推的话必须把另一维整个推下去,这个能不能实现我不知道,反正我现在不会写。于是就没写带pushdown的。
其实二维线段树的思想就是一维线段树的点当成一维,想明白了并不难,就是代码写起来挺麻烦。
这题用二维树状数组做代码就短多了。树状数组c变成了二维,与一维类似,c[x][y]表示c[x-lowbit(x)][y-lowbit(y)]这个矩阵内的和,两重循环更新,sum(x,y)求[1,x],[1,y]这个矩阵的和,最后答案再用容斥原理减一下。
二维线段树
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<vector> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #include<algorithm> using namespace std; typedef long long LL; const int MAXN=1030; const int MAXNODE=MAXN*4; const LL MOD=1000000007; int N,M; struct SegmentTree{ int sum[MAXNODE][MAXNODE]; void build_sub(int o,int L,int R,int id){ sum[id][o]=0; if(L>=R) return; int mid=L+(R-L)/2; if(L<=mid) build_sub(o<<1,L,mid,id); if(R>mid) build_sub(o<<1|1,mid+1,R,id); } void build(int o,int L,int R){ build_sub(1,1,M,o); if(L>=R) return; int mid=L+(R-L)/2; if(L<=mid) build(o<<1,L,mid); if(R>mid) build(o<<1|1,mid+1,R); } void update_sub(int o,int L,int R,int ql,int qr,int id,int v){ sum[id][o]+=v; if(L>=R) return; int mid=L+(R-L)/2; if(ql<=mid) update_sub(o<<1,L,mid,ql,qr,id,v); if(qr>mid) update_sub(o<<1|1,mid+1,R,ql,qr,id,v); } void update(int o,int L,int R,int ql,int qr,int subl,int subr,int v){ update_sub(1,1,M,subl,subr,o,v); if(L>=R) return; int mid=L+(R-L)/2; if(ql<=mid) update(o<<1,L,mid,ql,qr,subl,subr,v); if(qr>mid) update(o<<1|1,mid+1,R,ql,qr,subl,subr,v); } int query_sub(int o,int L,int R,int ql,int qr,int id){ if(ql<=L&&qr>=R) return sum[id][o]; int mid=L+(R-L)/2; int ret=0; if(ql<=mid) ret+=query_sub(o<<1,L,mid,ql,qr,id); if(qr>mid) ret+=query_sub(o<<1|1,mid+1,R,ql,qr,id); return ret; } int query(int o,int L,int R,int ql,int qr,int subl,int subr){ if(ql<=L&&qr>=R) return query_sub(1,1,M,subl,subr,o); int mid=L+(R-L)/2; int ret=0; if(ql<=mid) ret+=query(o<<1,L,mid,ql,qr,subl,subr); if(qr>mid) ret+=query(o<<1|1,mid+1,R,ql,qr,subl,subr); return ret; } }tree; int main(){ freopen("in.txt","r",stdin); int op; while(scanf("%d",&op)!=EOF){ if(op==0){ int s; scanf("%d",&s); N=M=s; tree.build(1,1,N); } else if(op==1){ int x,y,a; scanf("%d%d%d",&x,&y,&a); x++; y++; tree.update(1,1,N,x,x,y,y,a); } else if(op==2){ int l,b,r,t; scanf("%d%d%d%d",&l,&b,&r,&t); l++; b++; r++; t++; printf("%d\n",tree.query(1,1,N,l,r,b,t)); } else break; } return 0; }
二维树状数组
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<vector> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #include<algorithm> using namespace std; typedef long long LL; const int MAXN=1030; const int MAXNODE=MAXN*4; const LL MOD=1000000007; int N; int c[MAXN][MAXN]; int lowbit(int x){ return x&(-x); } void add(int x,int y,int v){ for(int i=x;i<=N;i+=lowbit(i)) for(int j=y;j<=N;j+=lowbit(j)) c[i][j]+=v; } int sum(int x,int y){ int ret=0; for(int i=x;i>0;i-=lowbit(i)) for(int j=y;j>0;j-=lowbit(j)) ret+=c[i][j]; return ret; } int main(){ freopen("in.txt","r",stdin); int op; while(scanf("%d",&op)!=EOF){ if(op==0){ int s; scanf("%d",&s); N=s; memset(c,0,sizeof(c)); } else if(op==1){ int x,y,a; scanf("%d%d%d",&x,&y,&a); x++; y++; add(x,y,a); } else if(op==2){ int l,b,r,t; scanf("%d%d%d%d",&l,&b,&r,&t); l++; b++; r++; t++; printf("%d\n",sum(r,t)-sum(l-1,t)-sum(r,b-1)+sum(l-1,b-1)); } else break; } return 0; }