题目大意:
给出一个序列,有两种操作,一种是计算l到r的和,另一种是让l到r的数全部和x做异或运算。
做法:
很显然直接暴力是不可能的(但是这题刚刚出来的时候,很多人用暴力水过去了,后来加强的数据吧),又是两种操作,又想到了线段树。。但是这并不简单,异或操作该怎么处理?
异或是一种位运算,如果x的第j位是1,那么说明l到r的每个数的第j位都要反转,(0^1=1,1^1=0),如果是0,那么不变。既然是位运算,那么可不可以将每一位作为线段树单独维护呢?
好像可以呢!异或操作的话,相当于是一种区间操作,只需要将l到r的某些位进行反转操作不就行了吗?反转操作什么的,打上lazy tag不就OK啦,求和操作也可以计算出l到r的每一位上有多少个1来算出最后的和。
好,那么理一下思路,首先确定建立多少个线段树,数的范围是10^6,也就是说,我们最多只需要建立20个线段树即可,再写好线段树的bulid,update,query三个函数。每个节点上需要维护两个值,一个是该区间有多少个1(用于求和),一个是该区间是否反转(lazy tag)。
代码:
#include
#include
#include
#define N 100010
#define L(x) (x)<<1
#define R(x) (x)<<1|1
using namespace std;
struct node
{
int l,r,cnt,lazy;
node(long long ll,long long rr,long long c,long long la)
{
l=ll,r=rr,cnt=c,lazy=la;
}
node()
{
l=r=cnt=lazy=0;
}
}p[20][N*4];
long long a[N][20],num[N],two[22];
long long bulid(long long id,long long l,long long r,long long na)
{
if(l==r){p[na][id]=node(l,r,a[l][na],0);return a[l][na];}
long long mid=(l+r)/2;
long long cur=bulid(L(id),l,mid,na)+bulid(R(id),mid+1,r,na);
p[na][id]=node(l,r,cur,0);
return cur;
}
void revers(long long id,long long l,long long r,long long na)
{
if(p[na][id].l==l && p[na][id].r==r)
{
p[na][id].lazy=1-p[na][id].lazy;
p[na][id].cnt=p[na][id].r-p[na][id].l+1-p[na][id].cnt;
return ;
}
if(p[na][id].lazy)//lazy tag 下放
{
p[na][id].lazy=0;
p[na][L(id)].lazy=1-p[na][L(id)].lazy;
p[na][R(id)].lazy=1-p[na][R(id)].lazy;
p[na][L(id)].cnt=p[na][L(id)].r-p[na][L(id)].l+1-p[na][L(id)].cnt;
p[na][R(id)].cnt=p[na][R(id)].r-p[na][R(id)].l+1-p[na][R(id)].cnt;
}
long long mid=(p[na][id].l+p[na][id].r)/2;
if(mid=r) revers(L(id),l,r,na);
else revers(L(id),l,mid,na),revers(R(id),mid+1,r,na);
p[na][id].cnt=p[na][L(id)].cnt+p[na][R(id)].cnt;
}
long long query(long long id,long long l,long long r,long long na)
{
if(p[na][id].l==l && p[na][id].r==r) return p[na][id].cnt;
if(p[na][id].lazy)
{
p[na][id].lazy=0;
p[na][L(id)].lazy=1-p[na][L(id)].lazy;
p[na][R(id)].lazy=1-p[na][R(id)].lazy;
p[na][L(id)].cnt=p[na][L(id)].r-p[na][L(id)].l+1-p[na][L(id)].cnt;
p[na][R(id)].cnt=p[na][R(id)].r-p[na][R(id)].l+1-p[na][R(id)].cnt;
}
long long mid=(p[na][id].l+p[na][id].r)/2;
if(mid>=r) return query(L(id),l,r,na);
else if(mid0)
{
a[i][j++]=num[i]&1;
num[i]>>=1;
}
}
for(long long i=0;i<20;i++)
bulid(1,1,n,i);
long long m;
scanf("%I64d",&m);
while(m--)
{
long long ty;
scanf("%I64d",&ty);
if(ty==1)
{
long long a,b;
scanf("%I64d%I64d",&a,&b);
long long cur=0;
for(long long i=0;i<20;i++)
cur+=query(1,a,b,i)*two[i];
cout<>=1)
{
if(x&1) revers(1,a,b,i);
}
}
}
return 0;
}