HDOJ 1892 See you~(二维树状数组)


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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值