题目链接:CF 242E
题目大意:
长度为n的数列,对区间[l,r]有两种操作:
- 1对区间求和并输出
- 2对区间异或x
分析:
如果线段树只维护区间合,显然不能直接进行异或.
于是就考虑二进制拆位,主要的思路就是将一个数,拆成若干个二进制位,然后对于异或操作,就转换成了每一位上的异或操作.
每一次异或, 对于给定的x, 如果x的第i位是1, 那么就将给定的区间内0,1翻转.
以下是代码:
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define Fi first
#define Se second
#define ll long long
#define inf 0x3f3f3f3f
#define lowbit(x) (x&-x)
#define PLL pair<ll,ll>
#define PII pair<int,int>
#define l_inf 0x3f3f3f3f3f3f3f
#define mmin(a,b,c) min(a,min(b,c))
#define mmax(a,b,c) max(a,max(b,c))
#define debug(a) cout<<#a<<"="<<a<<endl;
#define Sc_P(x) scanf("%d%d",&x.Fi,&x.Se)
#define Sc_PL(x) scanf("%lld%lld",&x.Fi,&x.Se)
#define debug2(a,b) cout<<#a<<"="<<a<<" "<<#b<<"="<<b<<endl;
using namespace std;
const int N=1e5+10;
const int maxn=30;
int cnt1[N<<2][maxn],cnt2[N<<2][maxn],lazy[N<<2];//cnt1 是该节点1的个数 cnt2是该节点0的个数
void push_up(int l,int r,int k)
{
if(l==r) return ;
for(int i=0;i<maxn;i++)
{
cnt1[k][i]=cnt1[k<<1][i]+cnt1[k<<1|1][i];
cnt2[k][i]=cnt2[k<<1][i]+cnt2[k<<1|1][i];
}
}
void build(int l,int r,int k)
{
if(l==r)
{
int val,i=0;
scanf("%d",&val);
for(int i=0;i<maxn;i++)
{
if(val&1) cnt1[k][i]++;
else cnt2[k][i]++;
val>>=1;
}
return ;
}
int m=(l+r)>>1;
build(l,m,k<<1);
build(m+1,r,k<<1|1);
push_up(l,r,k);
}
void update_cnt(int cnt1[maxn],int cnt2[maxn],int val)
{
int i=0;
while(val)
{
if(val&1)
swap(cnt1[i],cnt2[i]);
i++;val>>=1;
}
}
void push_down(int l,int r,int k)
{
if(l==r)
{
lazy[k]=0;
return ;
}
int s1=lazy[k]^lazy[k<<1];
int s2=lazy[k]^lazy[k<<1|1];
update_cnt(cnt1[k<<1],cnt2[k<<1],lazy[k]);
update_cnt(cnt1[k<<1|1],cnt2[k<<1|1],lazy[k]);
lazy[k]=0;
lazy[k<<1]=s1;
lazy[k<<1|1]=s2;
}
void update(int l,int r,int L,int R,int k,int val)
{
if(lazy[k]) push_down(l,r,k);
if(l>=L&&r<=R)
{
lazy[k]^=val;
int i=0;
while(val)
{
if(val&1)
swap(cnt1[k][i],cnt2[k][i]);
i++;val>>=1;
}
return ;
}
if(l==r) return ;
int m=(l+r)>>1;
if(L<=m)update(l,m,L,R,k<<1,val);
if(R>m) update(m+1,r,L,R,k<<1|1,val);
push_up(l,r,k);
}
ll query(int l,int r,int L,int R,int k)
{
if(lazy[k]) push_down(l,r,k);
if(l>=L&&r<=R)
{
ll ans=0;
for(int i=0;i<maxn;i++)
{
ans+=(1ll<<i)*cnt1[k][i];
}
return ans;
}
if(l==r) return 0;
int m=(l+r)>>1;
ll ans=0;
if(L<=m) ans+=query(l,m,L,R,k<<1);
if(R>m) ans+=query(m+1,r,L,R,k<<1|1);
return ans;
}
int main()
{
int n;scanf("%d",&n);
build(1,n,1);
int m;scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int sta,x,l,r;
scanf("%d%d%d",&sta,&l,&r);
if(sta==1)
{
cout<<query(1,n,l,r,1)<<endl;
}
else
{
scanf("%d",&x);
update(1,n,l,r,1,x);
}
}
return 0;
}
/*
7 9 0 13 7
7 12 5 8 2
5
7 9 0 13 7
8
2 2 5 5
1 1 5
2 1 2 10
1 2 3
*/