hdu1892(二维树状数组)

See you~

Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 3726    Accepted Submission(s): 1168

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1892
Problem Description
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
 

解题思路:
二维树状数组的应用。注意下减法和移动的时候,如果要求减去或移动的书数小于n1,那么把现有书全部移走,当前位置为0。这里困惑了好久,详见程序注释部分,后来想到它为什么是错的,因为这是一个树状数组,树状数组存储的不是当前这个位置的数,而是某一连续区间的和,所以要想概率老师讲的那样,按面积来求该位置的值。
这题还有一个比较巧妙的地方,就是题目说初始时每个位置都是1。先把每个位置初始化成0,然后用二维树状数组进行加1操作,比直接每个位置赋为1要好得多。


完整代码:
#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cstring>
#include <climits>
#include <cassert>
#include <complex>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
using namespace std;

#pragma comment(linker, "/STACK:102400000,102400000")

typedef long long LL;
typedef double DB;
typedef unsigned uint;
typedef unsigned long long uLL;

/** Constant List .. **/ //{

const int MOD = int(1e9)+7;
const int INF = 0x3f3f3f3f;
const LL INFF = 0x3f3f3f3f3f3f3f3fLL;
const DB EPS = 1e-9;
const DB OO = 1e20;
const DB PI = acos(-1.0); //M_PI;

string str;

const int maxn = 1003;
int maps[maxn][maxn];

int lowbit(int x)
{
    return x & (-x);
}

void add(int x , int y , int d)
{
    for(int i = x ; i < maxn ; i += lowbit(i))
    {
        for(int j = y ; j < maxn ; j += lowbit(j))
        {
            maps[i][j] += d;
        }
    }
}

void init()
{
    memset(maps , 0 , sizeof(maps));
    for(int i = 1 ; i < maxn; i ++)
    {
        for(int j = 1 ; j < maxn ; j ++)
        {
            add(i , j , 1);
        }
    }
}


int sum(int x , int y)
{
    int res = 0;
    for(int i = x ; i > 0 ; i -= lowbit(i))
    {
        for(int j = y ; j > 0 ; j -= lowbit(j))
        {
            res += maps[i][j];
        }
    }
    return res;
}

int getsum(int x , int y)
{
    return sum(x + 1 , y + 1) - sum(x , y + 1) - sum(x + 1 , y) + sum(x , y);
}

int main()
{
    #ifdef DoubleQ
    freopen("in.txt","r",stdin);
    #endif
    int T;
    scanf("%d",&T);
    int x1 , y1 , x2 , y2 , n1;
    int cas = 1;
    while(T--)
    {
        printf("Case %d:\n",cas++);
        init();
        int q;
        scanf("%d",&q);
        while(q--)
        {
            cin >> str;
            if(str[0] == 'S')
            {
                scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
                if(x1 > x2)
                    swap(x1 , x2);
                if(y1 > y2)
                    swap(y1 , y2);
                cout << sum(x2 + 1 , y2 + 1) - sum(x1 , y2 + 1) - sum(x2 + 1 ,y1) + sum(x1 , y1) << endl;
            }
            else if(str[0] == 'A')
            {
                scanf("%d%d%d",&x1,&y1,&n1);
                add(x1 + 1 , y1 + 1 , n1);
            }
            else if(str[0] == 'D')
            {
                scanf("%d%d%d",&x1,&y1,&n1);
                /*
                if(maps[x1+1][y1+1] < n1)
                    n1 = maps[x1+1][y1+1];
                */
               
                int k = getsum(x1 , y1);
                n1 = min(n1 , k);
                
                add(x1 + 1 , y1 + 1 , -n1);
            }
            else if(str[0] == 'M')
            {
                scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&n1);
                /*
                if(maps[x1+1][y1+1] < n1)
                    n1 = maps[x1+1][y1+1];
                */
                
                int k = getsum(x1 , y1);
                n1 = min(n1 , k);
                
                add(x1 + 1 , y1 + 1 , -n1);
                add(x2 + 1 , y2 + 1 , n1);
            }

        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值