CF242E XOR on Segment
CF242E XOR on Segment
题意翻译
-
给定nn 个数的序列 aa。mm 次操作,操作有两种:
- 求 \displaystyle\sum_{i=l}^r a_ii=l∑rai。
- 把 a_l\sim a_ra**l∼a**r 异或上 xx。
- 1\le n\le 10^51≤n≤105,1\le m\le 5\times 10^41≤m≤5×104,0\le a_i\le 10^60≤a**i≤106,1\le x\le 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\n",query(1,1,n,x,y));
else
{
scanf("%lld",&k);
update(1,1,n,x,y,k);
}
}
return 0;
}