HDU 5892 Resident Evil(状态压缩+树状数组)

来源:互联网 发布:python中的readline 编辑:程序博客网 时间:2024/06/08 06:12

Resident Evil

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 709    Accepted Submission(s): 180


Problem Description

The Umbrella Company has developed a new biochemical virus secretly. Lyon, a staff of the company, happened to find out the conspiracy and his company is now stopping him from discovering further evidence by releasing biochemical monster in his city (don’t ask me why the company is using this weird method).

The city can be described as an n*n grids. The Umbrella Company has 50 kinds of biochemical monster in total. The company will specify the type, quantity of biochemical monster and the rectangle area to put monster. For example, if the specified rectangle area has upper left corner (1, 1) and bottom right corner of (3, 3), and the company wishes to put 3 of A monster, 2 of B monster and 1 of C monster in it, then 3 of A monster, 2 of B monster and 1 of C monster is added to each and every grid inside the area.

However, Lyon risk his life of finding evidence by searching certain rectangle area. By doing this, all monsters inside the area would gather to him. He has two way of dealing with monster. If the number of a certain kind of monster is even, then he would choose to hide, otherwise withdraw.

 

Input

A line containing n and m (1<=n<=3000 1<=m<=100000). Representing the size of the city and the number of operations.

  Then m lines of operation and there are only two kinds of operation.

Letter ‘P’ means to release monster, followed by 4 integers x1, y1, x2, y2 (1<=x1, y1, x2, y2<=n) , describing the upper left corner and bottom right corner of the area. Then an integer K(1<=K<=50), meaning there will be k pair of number (A, B) given next. A (1<=A<=50) indicates the kind of the monster and B (1<=b<=100000) indicates the number of this kind being added to this area.

Letter ‘Q’ represents the query operation, followed by 4 integers x1, y1, x2, y2 (1<=x1, y1, x2, y2<=n), describing the upper left corner and bottom right corner of the area.

Output

For every ‘Q’ operation. Print 50 number in a line, meaning the kind of action he would take for different kinds of monsters. 1 represents hiding and 2 represents withdrawing.

Sample Input

2 2P 1 1 2 2 1 1 1 Q 1 1 1 1

Sample Output

2 1 1 1 1 1 ........1 (one '2' and forty-nine '1')

Source

2016 ACM/ICPC Asia Regional Shenyang Online


        看到题目标题:Resident Evil,我就知道自己一定要拿下这道题,果然是个硬骨头……

        大致题意是,有两种操作,P是在一个矩形区域内每个小格子中放相同种类及数量的生化怪兽,Q则是让你输出某一矩形区域内所有生化怪兽总和的的奇偶性,生化怪兽总共有50种。首先,50种生化怪兽的奇偶性很容易想到用状态压缩去表示,而奇偶性的添加变化则刚好对应位运算中的异或,一切看似理所当然。但是真正实现起来发现,异或统计区间和并不像通常理解的那样。

        首先,我们当然选择用树状数组来统计区间和。首先用一维来说方便理解。根据树状数组的性质,举例来说,如果对区间[1,4]的所有数都异或一个数字,那么c[1]将会异或一次、c[2]两次、c[3]一次、c[4]四次。我们知道,一个数异或另一个数字偶数次,等于没有异或,那么这样子可以知道,改变的只有1,3。推广开来,就是对于一个区间[l,r]异或对于树状数组c来说,真正改变的只有c[l]、c[l+2]、c[l+4]……即只有与左端点奇偶性相同的c改变。而且根据异或的性质,异或奇数次等于异或一次,即与左端点奇偶性相同的点的c值都要异或一次,而奇偶性不同的点不需要异或。

        看到这里,你可能会觉得有点熟悉,相当于隔一个数字异或一个,和上次那道隔k个数字修改的题目差不多,但在定义上有点区别。我们这里讨论的树状数组的c数组,并不是一个直接a的原数组。即,c数组就是一个a的类前缀和数组。这个是很容易搞混和不好理解的地方。理解了这个,我们要做到只对奇偶性相同的异或一次就只需要把一个树状数组变成两个,一个表示奇数,一个表示偶数。在修改的时候,在对应奇偶的树状数组的左端点处单点修改,然后在右端点的右边一个位置再单点修改,就可以使得对于区间[l,r]内的元素的c值都异或了一次,而其他部分不异或。再次强调,这里的修改与普通树状数组的差分区间修改不一样,c的含义是一个类前缀和。

        查询的时候就和上一道题类似了,对于端点为奇数的区间,对应查询奇数树状数组的值即可。理解了一维之后,转化成二维即可,对应的再增加两个树状数组。具体的见代码。代码如下:

#include<iostream>#include<cstdio>#include<algorithm>#include<cstdlib>#include<cmath>#include<cstring>#include<iomanip>#define LL long long#define N 3001using namespace std;int n,m;struct DifferenceBIT{LL c[N][N][2][2];//树状数组设置为四维,本身二维,加端点奇偶二维inline int lowbit(int x){return x&-x;}inline void updata(int x,int y,LL k){for (int i=x;i<=n;i+=lowbit(i))            for (int j=y;j<=n;j+=lowbit(j))                c[i][j][x&1][y&1]^=k;//只修改对应奇偶性的树状数组}inline LL getsum(int x,int y){LL ans=0;for (int i=x;i;i-=lowbit(i))            for (int j=y;j;j-=lowbit(j))                ans^=c[i][j][x&1][y&1];//查询也只查询对应奇偶性的树状数组return ans;}} BIT;int main(){    while (~scanf("%d%d",&n,&m))    {        int x1,y1,x2,y2;        char op; scanf("%c",&op);        while (op=='\n') scanf("%c",&op);        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);        if (op=='P')        {            int k;LL num=0;            scanf("%d",&k);            while (k--)            {                int x,y; scanf("%d%d",&x,&y);                if (y&1) num^=((LL)1<<--x);//状态压缩记录生化怪兽的奇偶性            }            BIT.updata(x1,y1,num);//对于c数组的单点修改,并不是区间修改            BIT.updata(x1,y2+1,num);            BIT.updata(x2+1,y1,num);            BIT.updata(x2+1,y2+1,num);        } else        {//结果也是异或出来的            LL res=BIT.getsum(x1-1,y1-1)^BIT.getsum(x1-1,y2)^BIT.getsum(x2,y1-1)^BIT.getsum(x2,y2);            for (int i=0;i<50;i++)                if (res&((LL)1<<i)) printf("2 "); else printf("1 ");            puts("");        }    }    return 0;}