2021牛客暑期多校训练营3 I-Kuriyama Mirai and Exclusive Or (差分+位运算)
Posted 昵称很长很长真是太好了
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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+(l−i))
题解:
我们发现
对于1操作,直接差分即可
对于2操作,我们每次取 lowbit(x) ,设lowbit(x)为
2
k
2^k
2k,
对于
i
−
l
<
2
k
i-l<2^k
i−l<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+i−l)=a xor x xor (i−l).
也就是说区间
[
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....,2k−1
异或
0
,
1
,
2
,
3....
,
2
k
−
1
0,1,2,3....,2^k-1
0,1,2,3....,2k−1这个我们可以在起始点打一个标记即可,即
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+2i−1−1] 分别异或
[
0
,
2
i
−
1
−
1
]
[ 0,2^i-1 -1]
[0,2i−1−1]
区间
[
j
+
2
i
−
1
,
j
+
j
+
2
i
−
1
]
[j+2^i-1,j+j+2^i -1]
[j+2i−1,j+j+2i−1] 先分别异或
[
0
,
2
i
−
1
−
1
]
[0,2^i-1 -1]
[0,2i−1−1],再同时异或上
2
i
−
1
2^i-1
2i−1
#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])<<" ";
以上是关于2021牛客暑期多校训练营3 I-Kuriyama Mirai and Exclusive Or (差分+位运算)的主要内容,如果未能解决你的问题,请参考以下文章
2021牛客暑期多校训练营1 - F - Find 3-friendly Integers - 题解