题意:对一个矩阵不停的更新和查询,每次查询得到一个子矩阵的和。
最基础的二维线段树。感觉还不是很难,和最开始自己猜测的样子差不多——在一维的基础上,对每一个节点加上一棵子树,还是很形象的。
第一维还是表示X轴,然后每一个节点的子树表示在这一段区间内Y轴上的情况。
写完之后感觉自己以前的一维线段树有很多不足,冗杂的没有任何意义的计算不仅浪费了时间也浪费了大量的内存,是时候好好整理一下了。
PS:要是走之前就把这道题过了,也不至于现场赛时墨迹了那么久才出题。A掉之后去Status里面翻了一下,第一名竟然才跑了97ms,被甩了N条街唉。
#include <iostream> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cstring> using namespace std; int st[2048][2048]; void updata_y(int s1,int s2,int T,int B,int x,int y,int a,int S) { st[s1][s2] += a; if(T == B) return ; int mid = (T + B)>>1; if(y <= mid) { updata_y(s1,s2<<1,T,mid,x,y,a,S); } else { updata_y(s1,s2<<1|1,mid+1,B,x,y,a,S); } } void updata_x(int s1,int s2,int L,int R,int x,int y,int a,int S) { updata_y(s1,s2,0,S-1,x,y,a,S); if(L == R) return ; int mid = (L + R)>>1; if(x <= mid) { updata_x(s1<<1,s2,L,mid,x,y,a,S); } else { updata_x(s1<<1|1,s2,mid+1,R,x,y,a,S); } } int query_y(int s1,int s2,int T,int B,int l,int r,int t,int b,int S) { if(T == t && B == b) { return st[s1][s2]; } int mid = (B + T)>>1; if(b <= mid) { return query_y(s1,s2<<1,T,mid,l,r,t,b,S); } if(mid < t) { return query_y(s1,s2<<1|1,mid+1,B,l,r,t,b,S); } return query_y(s1,s2<<1,T,mid,l,r,t,mid,S) + query_y(s1,s2<<1|1,mid+1,B,l,r,mid+1,b,S); } int query_x(int s1,int s2,int L,int R,int l,int r,int t,int b,int S) { if(L == l && R == r) { return query_y(s1,s2,0,S-1,l,r,t,b,S); } int mid = (L + R)>>1; if(r <= mid) { return query_x(s1<<1,s2,L,mid,l,r,t,b,S); } if(mid < l) { return query_x(s1<<1|1,s2,mid+1,R,l,r,t,b,S); } return query_x(s1<<1,s2,L,mid,l,mid,t,b,S) + query_x(s1<<1|1,s2,mid+1,R,mid+1,r,t,b,S); } int main() { int n,m; int x,y,a; int l,r,t,b; while(scanf("%d",&n) && n != 3) { if(n == 0) { scanf("%d",&m); memset(st,0,sizeof(st)); } else if(n == 1) { scanf("%d %d %d",&x,&y,&a); updata_x(1,1,0,m-1,x,y,a,m); } else if(n == 2) { scanf("%d %d %d %d",&l,&t,&r,&b); printf("%d\n",query_x(1,1,0,m-1,l,r,t,b,m)); } } return 0; }