HDU_1892_See you~
假设每个格子代表一个数A[i][j],i是横坐标,j是纵坐标,左上角的坐标为(1,1)我们要求红色区域元素之和,设sum(i,j)表示以i,j坐标为右下角坐标,以0,0为左上角坐标矩形内的元素之和,
sum(c,d):绿色+黄色+红色+蓝色
sum(c,b-1):绿色+蓝色
sum(a-1,d):绿色+黄色
sum(a-1,b-1):绿色
则红色区域元素之和=sum(c,d)-sum(c,b-1)-sum(a-1,d)+sum(a-1,b-1)
#include<iostream> #include<cstring> using namespace std; #define N 1005 int C[N][N]; //使用C之前,先清0 int sum(int x,int y) //x是横坐标,y是纵坐标 { int ret=0,i,j; for(i=x;i>0;i-=(i&-i)) for(j=y;j>0;j-=(j&-j)) ret+=C[i][j]; return ret; } void add(int x,int y,int d) //d是需要增加的值 { int i,j; for(i=x;i<N;i+=(i&-i)) for(j=y;j<N;j+=(j&-j)) C[i][j]+=d; } int main() { int t,n,a,b,c,d,e,i,j,k,v; char s[5]; scanf("%d",&t); for(k=1;k<=t;++k) { scanf("%d",&n); printf("Case %d:\n",k); for(i=1;i<N;++i) //据说int类型的,用这个会比memset快 for(j=1;j<N;++j) C[i][j]=0; /*注意树状数组的坐标是从1开始的,而题目中x,y的坐标都是从0开始的,自增1吧,少年*/ for(i=1;i<N;++i) for(j=1;j<N;++j) add(i,j,1); while(n--) { scanf("%s",s); if(s[0]=='S') { scanf("%d%d%d%d",&a,&b,&c,&d); if(a<c) swap(a,c); //不管给哪条对角线,都这样算 if(b<d) swap(b,d); printf("%d\n",sum(a+1,b+1)-sum(a+1,d)-sum(c,b+1)+sum(c,d)); } else if(s[0]=='A') { scanf("%d%d%d",&a,&b,&c); add(a+1,b+1,c); } else if(s[0]=='D') { scanf("%d%d%d",&a,&b,&c); v=sum(a+1,b+1)-sum(a,b+1)-sum(a+1,b)+sum(a,b);//有可能出现数量不足的情况 c=v<c?v:c; add(a+1,b+1,-c); } else { scanf("%d%d%d%d%d",&a,&b,&c,&d,&e); v=sum(a+1,b+1)-sum(a,b+1)-sum(a+1,b)+sum(a,b);//有可能出现数量不足的情况 e=v<e?v:e; add(a+1,b+1,-e); add(c+1,d+1,e); } } } return 0; }