CF242E XOR on Segment

CF242E XOR on Segment

洛谷传送门

题意翻译

  • 给定nn 个数的序列 aa。mm 次操作,操作有两种:

    1. 求 displaystylesum_{i=l}^r a_ii=lrai
  1. 把 a_lsim a_ra**la**r 异或上 xx
  • 1le nle 10^51≤n≤105,1le mle 5 imes 10^41≤m≤5×104,0le a_ile 10^60≤a**i≤106,1le xle 10^61≤x≤106。

题解:

由于位运算和求和操作不兼容,所以不是裸的线段树的题。

介绍一种操作:拆位。

具体一些,因为位运算和求和不兼容,但是保证位运算正确可以由此维护和(按位乘2的整数次幂再相加),反之,只维护和的正确性不能保证位运算正确。所以我们用拆位来维护每一位。

为了保证和的可求性,我们对于每个节点维护(tree[pos].val[i])表示当前节点的第(i)位有多少个1.

这时,如果要区间异或上一个(x),如果(x)的对应位为1就要取反,反之不变。这样的话,我们就维护好了位运算的正确性。要求和的时候再累加即可。

记得开longlong

代码:

#include<cstdio>
#define lson pos<<1
#define rson pos<<1|1
#define int long long
using namespace std;
const int maxn=1e5+5;
int n,m;
int a[maxn];
struct segment_tree
{
	int val[22];
	int sum;
}tree[maxn<<2];
int lazy[maxn<<2];
void pushup(int pos)
{
	for(int i=0;i<=20;i++)
		tree[pos].val[i]=tree[lson].val[i]+tree[rson].val[i];
	tree[pos].sum=tree[lson].sum+tree[rson].sum;
}
void build(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	if(l==r)
	{
		for(int i=0;i<=20;i++)
			if(a[l]>>i&1)
				tree[pos].val[i]=1;
		tree[pos].sum=a[l];
		return;
	}
	build(lson,l,mid);
	build(rson,mid+1,r);
	pushup(pos);
}
int qpow(int a,int b)
{
	int ret=1;
	while(b)
	{
		if(b&1)
			ret*=a;
		a*=a;
		b>>=1;
	}
	return ret;
}
void mark(int pos,int l,int r,int k)
{
	int tmp=0;
	for(int i=0;i<=20;i++)
		if(k>>i&1)
			tree[pos].val[i]=(r-l+1)-tree[pos].val[i];
	for(int i=0;i<=20;i++)
		tmp+=(qpow(2,i)*tree[pos].val[i]);
	tree[pos].sum=tmp;
	lazy[pos]^=k;
}
void pushdown(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	mark(lson,l,mid,lazy[pos]);
	mark(rson,mid+1,r,lazy[pos]);
	lazy[pos]=0;
}
void update(int pos,int l,int r,int x,int y,int k)
{
	int mid=(l+r)>>1;
	if(x<=l && r<=y)
	{
		mark(pos,l,r,k);
		return;
	}
	if(lazy[pos])
		pushdown(pos,l,r);
	if(x<=mid)
		update(lson,l,mid,x,y,k);
	if(y>mid)
		update(rson,mid+1,r,x,y,k);
	pushup(pos);
}
int query(int pos,int l,int r,int x,int y)
{
	int ret=0;
	int mid=(l+r)>>1;
	if(x<=l && r<=y)
		return tree[pos].sum;
	if(lazy[pos])
		pushdown(pos,l,r);
	if(x<=mid)
		ret+=query(lson,l,mid,x,y);
	if(y>mid)
		ret+=query(rson,mid+1,r,x,y);
	return ret;
}
signed main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	build(1,1,n);
	scanf("%lld",&m);
	for(int i=1;i<=m;i++)
	{
		int opt,x,y,k;
		scanf("%lld%lld%lld",&opt,&x,&y);
		if(opt==1)
			printf("%lld
",query(1,1,n,x,y));
		else
		{
			scanf("%lld",&k);
			update(1,1,n,x,y,k);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/fusiwei/p/14034122.html