http://acm.hdu.edu.cn/showproblem.php?pid=1892
题意:有一个矩形书架,被分成很多个格子,刚开始的时候每一个格子都会有一本书。现在给出ADMS四种操作,DM要注意,如果所删除或者所移动的数量超过原来格子中书本数,最多也只能删除或者移动这些书本。还有MS操作时,给出的左边不一定是左上角和右下角的坐标。
由于给出的坐标可能会出现0,但是树状数组不能处理0的情况,所以要在一开始把所有坐标都统一加1,那么就相当于变换坐标系,不改变结果。并且由于不知道这个书架到底多大,所以在开树状数组的时候,按照最大的数据1000来处理。再求一个左上角不是(1,1)的矩阵的时候,要注意方法,可以看程序。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define VN 1010
const int n = 1005;
using namespace std;
int N, c[VN][VN], a[VN][VN];
int lowbit(int x)
{
return x&(-x);
}
void add(int x, int y, int d)
{
int i = y;
while(x <= n)
{
y = i;
while(y <= n)
{
c[x][y] += d;
y += lowbit(y);
}
x += lowbit(x);
}
}
int query(int x, int y)
{
int i = y, sum = 0;
while(x > 0)
{
y = i;
while(y > 0)
{
sum += c[x][y];
y -= lowbit(y);
}
x -= lowbit(x);
}
return sum;
}
int main()
{
int T, cnt, x1, y1, x2, y2, x, y, d;
char ch[3];
scanf("%d", &T);
cnt = 0;
while (T--)
{
scanf("%d", &N);
memset(c, 0, sizeof(c));
memset(a, 0, sizeof(a));
for (int i = 1; i <= n; i++)
for (int j =1; j <= n; j++)
{
add(i, j, 1);
a[i][j] = 1;
}
printf("Case %d:\n", ++cnt);
for (int i = 1; i <= N; i++)
{
scanf("%s", ch);
if (ch[0] == 'S')
{
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
x1++;
y1++;
x2++;
y2++;
if (x1 > x2) swap(x1, x2);
if (y1 > y2) swap(y1, y2);
int ans = query(x2, y2) - query(x2, y1-1) - query(x1-1, y2) + query(x1-1, y1-1);
printf("%d\n", ans);
}
if (ch[0] == 'A')
{
scanf("%d%d%d", &x, &y, &d);
x++;
y++;
add(x, y, d);
a[x][y] += d;
}
if (ch[0] == 'D')
{
scanf("%d%d%d", &x, &y, &d);
x++;
y++;
if (d > a[x][y]) d = a[x][y];
add(x, y, -d);
a[x][y] -= d;
}
if (ch[0] == 'M')
{
scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &d);
x1++;
y1++;
x2++;
y2++;
if (d > a[x1][y1]) d = a[x1][y1];
add(x1, y1, -d);
add(x2, y2, d);
a[x1][y1] -= d;
a[x2][y2] += d;
}
}
}
return 0;
}