2021牛客暑期多校训练营3 I-Kuriyama Mirai and Exclusive Or (差分+位运算)

题意:
两个操作:
1.给区间 [ l , r ] [l,r] [l,r]之间的数异或 x x x
2.给区间 [ l , r ] [l,r] [l,r]之间异或 ( x + ( l − i ) ) (x+(l-i) ) (x+(li))
题解:
我们发现
对于1操作,直接差分即可
对于2操作,我们每次取 lowbit(x) ,设lowbit(x)为 2 k 2^k 2k,
对于 i − l < 2 k i-l<2^k il<2k, a   x o r   ( x + i − l ) = a   x o r   x   x o r   ( i − l ) a\ xor\ (x+i-l)=a\ xor \ x\ xor\ (i-l) a xor (x+il)=a xor x xor (il).
也就是说区间 [ l , l + 2 k ) [l,l+2^k) [l,l+2k) ,先整体异或上 x x x,再依次异或上 0 , 1 , 2 , 3.... , 2 k − 1 0,1,2,3....,2^k-1 0,1,2,3....,2k1
异或 0 , 1 , 2 , 3.... , 2 k − 1 0,1,2,3....,2^k-1 0,1,2,3....,2k1这个我们可以在起始点打一个标记即可,即 b i t [ i ] [ k ] bit[i][k] bit[i][k]代表第i个位置开始依次异或上了 [ 0 , 2 k ) [0,2^k) [0,2k),重复上述操作即可,然后对于剩余的一段单独处理一下。

下面说的是对于bit如何处理。

把下标从 j j j开始长度为 2 i 2^i 2i的区间分解成 两个区间进行计算
分别为 区间 [ j , j + 2 i − 1 − 1 ] [j,j+2^{i-1} -1] [j,j+2i11] 分别异或 [ 0 , 2 i − 1 − 1 ] [ 0,2^{i-1} -1] [0,2i11]
区间 [ j + 2 i − 1 , j + j + 2 i − 1 ] [j+2^{i-1},j+j+2^i -1] [j+2i1,j+j+2i1] 先分别异或 [ 0 , 2 i − 1 − 1 ] [0,2^{i-1} -1] [0,2i11],再同时异或上 2 i − 1 2^{i-1} 2i1

#include<bits/stdc++.h>
#define endl '\n'
//#define int long long
using namespace std;
const int maxn=6e5+10;

int a[maxn],b[maxn];
int bit[maxn][22];

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    while(m--){
        int opt,l,r,x;
        cin>>opt>>l>>r>>x;
        if(opt==0){
            b[l]^=x;
            b[r+1]^=x;
        }
        else{
            for(int i=0;i<=19;i++){
                if((x>>i&1)&&(l+(1<<i)-1)<=r){
                    b[l]^=x;
                    b[l+(1<<i)]^=x;  //差分
                    bit[l][i]^=1;    //打标记 代表从这个位置开始[l,l+1,...l+2^(k) - 1] 分别异或了 [0,2,3,4...,2^(i)-1].
                    l+=(1<<i);
                    x+=(1<<i);
                }
            }
            for(int i=19;i>=0;i--){  //从大到小把剩余的块补起来
                if((l+(1<<i)-1)<=r){
                    b[l]^=x;
                    b[l+(1<<i)]^=x;  //同上操作
                    bit[l][i]^=1;
                    l+=(1<<i);
                    x+=(1<<i);
                }
            }
        }
    }
    for(int i=19;i>=1;i--){
        for(int j=1;j<=n;j++){
            if(!bit[j][i]) continue;
            bit[j][i-1]^=1;
            bit[j+(1<<(i-1))][i-1]^=1;
            //把 1 ~ 2^k 分解成 两个区间进行计算
            //分别为  区间[j,j+2^(i-1) -1] 分别异或 [0,2^(i-1) -1]
            // 区间[j+2^(i-1),j+j+2^(i) -1]  先分别异或 [0,2^(i-1) -1],再同时异或上2^(i-1)
            b[j+(1<<(i-1))]^=(1<<(i-1));
            b[j+(1<<i)]^=(1<<(i-1));
        }
    }
    for(int i=1;i<=n;i++){
        b[i]^=b[i-1];
        cout<<(a[i]^b[i])<<" ";
    }


}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值