See you~_树状数组

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

【题意】1000*1000个格子,每个格子里放一本书,可以增加,减少,移动,求给出矩阵内的书的数量

【思路】二维树状数组,要注意的是,从坐标0,0开始,为了避免while(0),都加一进行更新,减少的时候要比较当前的数量是否大于要减少的数量

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int N=1000+5;
int n;
int sum[N][N];
int lowbit(int x)
{
    return x&(-x);
}

void update(int x,int y,int a)
{
    while(x<N)
    {
        int t=y;
        while(t<N)
        {
            sum[x][t]+=a;
            t+=lowbit(t);
        }
        x+=lowbit(x);
    }
}
int get_sum(int x,int y)
{
    int res=0;
    while(x)
    {
        int t=y;
        while(t)
        {
            res+=sum[x][t];
            t-=lowbit(t);
        }
        x-=lowbit(x);
    }
    return res;
}
int get_a(int x,int y)
{
    return get_sum(x,y)-get_sum(x-1,y)-get_sum(x,y-1)+get_sum(x-1,y-1);
}

int main()
{
    int t,cas=1;
    scanf("%d",&t);
    while(t--)
    {
        printf("Case %d:\n",cas++);
        scanf("%d",&n);
        memset(sum,0,sizeof(sum));
        for(int i=1; i<=N; i++)
        {
            for(int j=1; j<=N; j++)
            {
                update(i,j,1);
            }
        }

        for(int i=1; i<=n; i++)
        {
            char s[10];
            int x,y,a,b,z;

            scanf("%s ",s);
            if(s[0]==‘A‘||s[0]==‘D‘)
            {
                scanf("%d%d%d",&x,&y,&a);
                if(s[0]==‘D‘) a=-min(a,get_a(x+1,y+1));//判断现在的数量是否多于要减少的数量,如果不是,就全搬走就可。
                update(x+1,y+1,a);
            }
            else if(s[0]==‘M‘)
            {
               scanf("%d%d%d%d%d",&x,&y,&a,&b,&z);
               z=min(z,get_a(x+1,y+1));
               update(x+1,y+1,-z);
               update(a+1,b+1,z);
            }
            else
            {
                scanf("%d%d%d%d",&x,&y,&a,&b);
                if(a<x) swap(a,x);
                if(b<y) swap(b,y);
                int tmp=get_sum(a+1,b+1)-get_sum(a+1,y)-get_sum(x,b+1)+get_sum(x,y);
                printf("%d\n",tmp);
            }
        }
    }

    return 0;
}
时间: 2024-10-22 22:42:25

See you~_树状数组的相关文章

BZOJ_3653_谈笑风生_树状数组

Description 设T 为一棵有根树,我们做如下的定义: ? 设a和b为T 中的两个不同节点.如果a是b的祖先,那么称“a比b不知道 高明到哪里去了”. ? 设a 和 b 为 T 中的两个不同节点.如果 a 与 b 在树上的距离不超过某个给定 常数x,那么称“a 与b 谈笑风生”. 给定一棵n个节点的有根树T,节点的编号为1 到 n,根节点为1号节点.你需 要回答q 个询问,询问给定两个整数p和k,问有多少个有序三元组(a;b;c)满足: 1. a.b和 c为 T 中三个不同的点,且 a为

BZOJ_5055_膜法师_树状数组+离散化

Description 在经历过1e9次大型战争后的宇宙中现在还剩下n个完美维度, 现在来自多元宇宙的膜法师,想偷取其中的三个维度为伟大的长者续秒, 显然,他能为长者所续的时间,为这三个维度上能量的乘积, 但目前的宇宙很不乐观,胡乱偷取可能造成维度的崩溃, 所以,他必须按逆序偷取这些维度,且在偷取中, 每次偷取的维度的能量必须严格小于他上次偷取的能量, 由于膜法师生活在多元宇宙,所以他可以让所有可能的偷取方案全部发生 题目描述 但他数学不好,所以找到了你帮他求出能为长者续几秒, 你要做的,就是在

[bzoj2131]免费的馅饼_树状数组

免费的馅饼 bzoj-2131 题目大意: 注释:$1\le n \le 10^5$,$1\le w \le 10^8$. 想法:首先,想到dp 状态:dp[i][j]表示i分钟在位置j的最大收益 优化优化 状态:dp[i]表示最后收到i的最大收益. 转移:顺序枚举i:1->n即可. 然后,我们尝试优化 对于这个状态我们会发现转移的时候有一个绝对值的死东西,我们将它拆开就有: 2*t[j]+pos[j]<=2*t[i]+pos[i]且2*t[j]-pos[j]<=2*t[i]-pos[i

[bzoj3529][Sdoi2014]数表_树状数组_莫比乌斯反演

数表 bzoj-3529 Sdoi-2014 题目大意:n*m的数表,第i行第j列的数是同时整除i和j的所有自然数之和.给定a,求数表中所有不超过a的和. 注释:$1\le n,m \le 10^5$. 想法:我们先不考虑那个a的限制:我们设f(i)表示整除i的自然数之和. $\sum\limits_{i=1}^n\sum\limits_{j=1}^m f(gcd(i,j))$ $\sum\limits_{i=1}^n\sum\limits_{j=1}^m f(d)\cdot [gcd(i,j)

[bzoj1103][POI2007]大都市meg_dfs序_树状数组

大都市meg bzoj-1103 POI-2007 题目大意:给定一颗n个点的树,m次操作.将一条路的边权更改成0:查询一个点到根节点的点权和.开始的时候所有边的边权都是1. 注释:$1\le n,m\le 2.5\cdot 10^5$. 想法:我们先拉出dfs序.其实严格来讲是出栈入栈序,就是每个点在序上出现两次的那个. 开始的时候入栈时的点权是1,出栈是-1.修改就是把出栈入栈都改成0.然后用树状数组查询前缀和即可. 最后,附上丑陋的代码... ... #include <iostream>

[bzoj3378][Usaco2004 Open]MooFest 狂欢节_树状数组

MooFest 狂欢节 bzoj-3378 Usaco-2004 Open 题目大意:给定一个n个数的a序列,每两个数之间有一个距离,两个点之间的权值为$max(a[i],a[j])*dis(i,j)$. 注释:$1\le n\le 2\cdot 10^4$. 想法:裙子说了,这种$max$和$min$的题通常要枚举这个$max$和$min$到底是多少. 这样的话我们就将所有点按权值从大到小排序. 往树状数组里插. 查询直接查询即可. 最后,附上丑陋的代码... ... #include <io

[bzoj3289]Mato的文件管理_莫队_树状数组

Mato的文件管理 bzoj-3289 题目大意:给定一个n个数的序列.m次询问:一段区间中的逆序对个数. 注释:$1\le n\,mle 5\cdot 10^4$. 想法: 开始想这个题的大佬们,给您点儿提示吧:$O(nlogn\sqrt(n))$可过哦! 所以这个题就是莫队的裸题了. 我们的莫队上的区间在动的时候随时更新树状数组上的信息即可.. 然后碰见了一整块区间,我们就直接求逆序对即可, 最后,附上丑陋的代码... ... #include <iostream> #include &l

敌兵布阵_树状数组

Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视. 中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Dere

YBT1540打鼹鼠_二维树状数组

1540:打鼹鼠_二维树状数组 时间限制: 1000 ms         内存限制: 524288 KB [题目描述] 这是一道模板题. 给出一个 n×m 的零矩阵 A,你需要完成如下操作: 1 x y k:表示元素 Ax,y自增 k: 2 a b c d:表示询问左上角为 (a,b),右下角为 (c,d) 的子矩阵内所有数的和. [输入] 输入的第一行有两个正整数 n,m: 接下来若干行,每行一个操作,直到文件结束. [输出] 对于每个 2 操作,输出一个整数,表示对于这个操作的回答. [输