J

题目描述

这里写图片描述

分块

2*3的矩形可以压成64以内的二进制数。
我们分块,对于每块,维护块内每个前缀异或的桶,以及整个块异或值,因为有区间修改还要有修改tag,然后便容易询问与修改。

#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=1000000+10,maxd=64;
int cnt[maxn/100+10][maxd+10],num[maxn/100+10],tag[maxn/100+10],belong[maxn],ac[20];
int id[20][20];
int a[maxn];
bool bz[maxn/100+10];
int i,j,k,l,t,n,m,r,q,wdc,B;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
void mark(int x,int v){
    bz[x]=1;
    tag[x]=v;
}
void down(int x){
    if (!bz[x]) return;
    int i;
    fo(i,(x-1)*B+1,min(B*x,n)) a[i]=ac[tag[x]];
    bz[x]=0;
}
void rebuild(int x){
    down(x);
    int i,t=0;
    fo(i,0,maxd-1) cnt[x][i]=0;
    fo(i,(x-1)*B+1,min(B*x,n)){
        t^=a[i];
        cnt[x][t]++;
    }
    num[x]=t;
}
int query(int j,int k){
    int i,t=0,ans=0,x;
    int l=belong[j],r=belong[k];
    if (l==r){
        fo(i,1,l-1){
            if (bz[i]){
                if (B%2) t^=ac[tag[i]];
            }
            else t^=num[i];
        }
        fo(i,(l-1)*B+1,min(l*B,n)){
            if (bz[l]) t^=ac[tag[l]];else t^=a[i];
            if (j<=i&&i<=k&&t==wdc) ans++;
        }
        return ans;
    }
    fo(i,1,l-1){
        if (bz[i]){
            if (B%2) t^=ac[tag[i]];
        }
        else t^=num[i];
    }
    fo(i,(l-1)*B+1,l*B){
        if (bz[l]) t^=ac[tag[l]];else t^=a[i];
        if (j<=i&&t==wdc) ans++;
    }
    fo(i,l+1,r-1){
        if (bz[i]){
            if ((ac[tag[i]]^t)==wdc) ans+=(B+1)/2;
            if (t==wdc) ans+=B/2;
            if (B%2) t^=ac[tag[i]];
        }
        else{
            ans+=cnt[i][wdc^t];
            t^=num[i];
        }
    }
    fo(i,(r-1)*B+1,k){
        if (bz[r]) t^=ac[tag[r]];else t^=a[i];
        if (t==wdc) ans++;
    }
    return ans;
}
void change(int j,int k,int v){
    int i;
    int l=belong[j],r=belong[k];
    if (l==r){
        down(l);
        fo(i,j,k) a[i]=ac[v];
        rebuild(l);
        return;
    }
    fo(i,l+1,r-1) mark(i,v);
    down(l);
    fo(i,j,l*B) a[i]=ac[v];
    rebuild(l);
    down(r);
    fo(i,(r-1)*B+1,k) a[i]=ac[v];
    rebuild(r);
}
int main(){
    freopen("ji.in","r",stdin);freopen("ji.out","w",stdout);
    n=read();m=read();
    wdc=0;
    fo(i,1,n)
        fo(j,1,m){
            t=read();
            wdc=wdc*2+t;
        }
    t=0;
    fd(i,n,1)
        fd(j,m,1)
            id[i][j]=t++;
    fo(i,1,n){
        ac[i]=0;
        fo(j,1,m) ac[i]+=(1<<id[i][j]);
    }
    fo(j,1,m){
        ac[j+n]=0;
        fo(i,1,n) ac[j+n]+=(1<<id[i][j]);
    }
    n=read();m=read();
    //B=floor(sqrt(n));
    //B=1;
    B=600;
    fo(i,1,n) belong[i]=(i-1)/B+1;
    fo(i,1,belong[n]){
        mark(i,1);
        rebuild(i);
    }
    while (m--){
        t=read();
        if (t==0){
            j=read();k=read();
            down(belong[j]);
            a[j]=ac[k];
            rebuild(belong[j]);
        }
        else if (t==1){
            j=read();k=read();
            printf("%d\n",query(j,k));
        }
        else{
            j=read();k=read();l=read();
            change(j,k,l);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值