HDU 5892 Resident Evil(二维BIT)

Description

给出一个n×nn×n的矩阵,有5050种动物,初始时矩阵每个位置都没有动物,mm次操作,操作分两种

P x1 y1 x2 y2 k a1 b1 ... ak bk:在子矩阵[x1,x2]×[y1,y2][x1,x2]×[y1,y2]的每个位置放bibi个第aiai种动物

Q x1 y1 x2 y2:Q x1 y1 x2 y2:查询子矩阵[x1,x2]×[y1,y2][x1,x2]×[y1,y2]所有位置这5050种动物数量之和的奇偶性

Input

第一行输入两个整数n,mn,m表示矩阵维数和查询数,之后mm行每行一组查询

(1n3103,1m105,1k50,1bi105)

Output

对于每组查询输出5050个整数,第ii个整数表示子矩阵中第i种动物数量之和的奇偶性(奇数输出22,偶数输出1

Sample Input

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

Sample Output

2 1 …. 1

Solution

把五十种动物的奇偶性用50500101压成一个状态,每次加入偶数的动物显然对答案没影响,加入奇数个动物等价于加入一个动物,子矩阵动物数量之和的奇偶性等价于每个位置该种动物数量奇偶性的异或和

首先看一维情况,即区间异或的操作和区间异或和的查询,由树状数组可以把这两种操作变成单点修改和前缀异或和查询,如果对区间[L,R][L,R]进行异或xx的操作,考虑该次操作对前缀异或和[1,y](LyR)的影响,显然如果yyL奇偶性相同那么影响为xx,否则影响为0,而该区间异或xx的操作在实现时是对L位置异或xx,并对R+1位置异或xx以消除对后面值的影响,故如果单点修改位置为奇数,那么该次修改只对该位置及其之后的奇数位置的前缀异或和有影响,偶数同理,那么如果直接把普通的树状数组的加法改成异或显然是不对的,因为对于一个偶数位置的前缀和,其前面奇数位置的修改也会被统计到,为避免这种情况,再加一维表示修改查询位置的奇偶性,把奇偶性不同的修改查询位置分成两个树状数组分别处理

对于二维情况,只需对一维情况做推广,对子矩阵[x1,x2]×[y1,y2]的修改变成对(x1,y1),(x1,y2+1),(x2+1,y1),(x2+1,y2+1)(x1,y1),(x1,y2+1),(x2+1,y1),(x2+1,y2+1)四个顶点的修改,对该子矩阵的查询也变成对以这四个顶点为右下角,(1,1)(1,1)位左上角的前缀子矩阵查询,每次修改点(x,y)(x,y)的值以及查询[1,x]×[1,y][1,x]×[1,y]的前缀异或和时,要根据x,yx,y奇偶性的不同分到四个树状数组中分别处理

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 3210
int n,m;
ll f[55];
struct BIT
{
    #define lowbit(x) (x&-x)
    ll b[2][2][maxn][maxn];
    void init()
    {
        memset(b,0,sizeof(b));
    }
    void update(int x,int y,ll v)
    {
        for(int i=x;i<=n;i+=lowbit(i))
            for(int j=y;j<=n;j+=lowbit(j))
                b[x&1][y&1][i][j]^=v;
    }
    ll query(int x,int y)
    {
        ll ans=0;
        for(int i=x;i;i-=lowbit(i))
            for(int j=y;j;j-=lowbit(j))
                ans^=b[x&1][y&1][i][j];
        return ans;
    }
}bit;
void Update(int x1,int y1,int x2,int y2,ll v)
{
    bit.update(x2,y2,v);
    bit.update(x1,y1,v);
    bit.update(x1,y2,v);
    bit.update(x2,y1,v);
}
void Query(int x1,int y1,int x2,int y2)
{
    ll ans=bit.query(x2,y2)^bit.query(x1,y1)^bit.query(x1,y2)^bit.query(x2,y1);
    for(int i=1;i<=50;i++)
        if(ans&f[i])printf("2 ");
        else printf("1 ");
    printf("\n");
}
int main()
{
    f[1]=2;
    for(int i=2;i<=50;i++)f[i]=2ll*f[i-1];
    while(~scanf("%d%d",&n,&m))
    {
        bit.init();
        while(m--)
        {
            char op[11];
            int x1,y1,x2,y2,k,kind,num;
            ll temp;
            scanf(" %s%d%d%d%d",op,&x1,&y1,&x2,&y2);
            if(op[0]=='P')
            {
                scanf("%d",&k);
                temp=0;
                while(k--)
                {
                    scanf("%d%d",&kind,&num);
                    if(num&1)temp^=f[kind];
                }
                Update(x1,y1,x2+1,y2+1,temp);
            }
            else Query(x1-1,y1-1,x2,y2);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值