CF242E XOR on Segment

CF242E XOR on Segment

区间异或不好直接维护,于是我们考虑将所有数二进制分解。

我们把每一位单独提出来做,那么对于每一位,异或要么不变,要么取反,而位与位之间的操作是独立的!建一棵线段树维护每一位的信息,那么只要维护:
1.区间取反(0变1,1变0)
2.区间求和

即可。这个利用线段树+标记能够很轻松的实现。

所以总复杂度为\(O(nk log n)\),其中k为二进制的位数,这里\(k ≤20\)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
 
using namespace std;
typedef long long ll;
const int N=400005;
inline 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 f*x;
}
int n,m,a[N];
ll val[21][N];
bool tag[21][N];

#define ls (p<<1)
#define rs (p<<1|1)
#define mid ((l+r)>>1)
void build(int l,int r,int p) {
	if(l==r) {
		for(int i=0;i<=20;i++) 
			if(a[l]&(1<<i)) 
				val[i][p]=1;
		return;
	} 
	build(l,mid,ls);
	build(mid+1,r,rs);
	for(int i=0;i<=20;i++)
		val[i][p]=val[i][ls]+val[i][rs];
}

void pushdw(int p,int l,int r,int i) {
	tag[i][ls]^=tag[i][p];
	tag[i][rs]^=tag[i][p];
	if(!tag[i][p]) return;
	val[i][ls]=mid-l+1-val[i][ls];
	val[i][rs]=r-mid-val[i][rs];
	tag[i][p]=0;
}

void modify(int l,int r,int L,int R,int i,int p) {
	if(L<=l&&r<=R) {
		val[i][p]=r-l+1-val[i][p];
		tag[i][p]^=1;
		return;
	}
	pushdw(p,l,r,i);
	if(L<=mid) modify(l,mid,L,R,i,ls);
	if(R>mid) modify(mid+1,r,L,R,i,rs);
	val[i][p]=val[i][ls]+val[i][rs];
}

ll query(int l,int r,int L,int R,int p) {
	if(L<=l&&r<=R) {
		ll ans=0;
		for(int i=0;i<=20;i++)
			ans+=(val[i][p]<<i);
		return ans;
	}
	for(int i=0;i<=20;i++)
		pushdw(p,l,r,i);
	ll ans=0;
	if(L<=mid) ans+=query(l,mid,L,R,ls);
	if(R>mid) ans+=query(mid+1,r,L,R,rs);
	return ans;
}
int main() {
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	build(1,n,1);
	m=read();
	while(m--) {
		int op=read(),l=read(),r=read();
		if(op==1) {
			printf("%lld\n",query(1,n,l,r,1));
		} else {
			int x=read();
			for(int i=0;i<=20;i++)
				if(x&(1<<i))
					modify(1,n,l,r,i,1);
		}
	}
	return 0;
}
posted @ 2020-10-30 08:19  ke_xin  阅读(35)  评论(0编辑  收藏  举报