题意:对一个矩阵不停的更新和查询,每次查询得到一个子矩阵的和。
最基础的二维线段树。感觉还不是很难,和最开始自己猜测的样子差不多——在一维的基础上,对每一个节点加上一棵子树,还是很形象的。
第一维还是表示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;
}