A - See you~ HDU - 1892 (二维树状数组入门题目)
Now I am leaving hust acm. In the past two and half years, I learned so many knowledge about Algorithm and Programming, and I met so many good friends. I want to say sorry to Mr, Yin, I must leave now ~~> .<~~. I am very sorry, we could not advanced to the World Finals last year.
When coming into our training room, a lot of books are in my eyes. And every time the books are moving from one place to another one . Now give you the position of the books at the early of the day. And the moving information of the books the day, your work is to tell me how many books are stayed in some rectangles.
To make the problem easier, we divide the room into different grids and a book can only stayed in one grid. The length and the width of the room are less than 1000. I can move one book from one position to another position, take away one book from a position or bring in one book and put it on one position.
Input
In the first line of the input file there is an Integer T(1<=T<=10), which means the number of test cases in the input file. Then N test cases are followed.
For each test case, in the first line there is an Integer Q(1<Q<=100,000), means the queries of the case. Then followed by Q queries.
There are 4 kind of queries, sum, add, delete and move.
For example:
S x1 y1 x2 y2 means you should tell me the total books of the rectangle used (x1,y1)-(x2,y2) as the diagonal, including the two points.
A x1 y1 n1 means I put n1 books on the position (x1,y1)
D x1 y1 n1 means I move away n1 books on the position (x1,y1), if less than n1 books at that position, move away all of them.
M x1 y1 x2 y2 n1 means you move n1 books from (x1,y1) to (x2,y2), if less than n1 books at that position, move away all of them.
Make sure that at first, there is one book on every grid and 0<=x1,y1,x2,y2<=1000,1<=n1<=100.
Output
At the beginning of each case, output "Case X:" where X is the index of the test case, then followed by the "S" queries.
For each "S" query, just print out the total number of books in that area .
Sample Input
2 3 S 1 1 1 1 A 1 1 2 S 1 1 1 1 3 S 1 1 1 1 A 1 1 2 S 1 1 1 2
Sample Output
Case 1: 1 3 Case 2: 1 4
题意:给定你一个书架,这个书架是二维来进行分割的,每一个小格子代表的是一是一个小区间。然后给你四个操作,分别是:S,A,M,D。A操作是在在XY区间中增加K本书。S操作是查询(x1,y1)到(x2,y2)区间中书本的数目。计算之前swap一下保证x1,y1是最小的,x2,y2是最大的。D操作是删除区间(x1,y1)中K本书籍,有一个特点是如果这个区间中书籍的数量小于K的话就清空这个区间的书籍就可以了。M操作是交换区间(x1,y1)到(x2,y2)K本书籍。如果区间值小于则选取最小的。
二维数组中的getsum是计算改点到(0,0)区间中书籍的总数。然后如果求区间(x1,y1)到(x2,y2)区间中书本的数目。
sum(a+1,b+1)-sum(a+1,d)-sum(c,b+1)+sum(c,d);左上角部分减的时候有重叠部分,所以加回来。
二维树状数组模板
#define N 1005
int C[N][N];
int sum(int x,int y)
{
int ret=0;
for(int i=x; i>0; i=i-(i&-i))
{
for(int j=y; j>0; j=j-(j&-j))
ret=ret+C[i][j];
}
return ret;
}
void add(int x,int y,int v)
{
for(int i=x; i<N; i=i+(i&-i))
{
for(int j=y; j<N; j=j+(j&-j))
C[i][j]=C[i][j]+v;
}
}
题目代码:
#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;
}
上一篇: Java基础-安装