Description
给定一个有(N)个正整数的初始序列,要求你进行(Q)次操作,每次操作由下列两种内容组成:
(1) (L) (R):询问(L)到(R)的区间和。
(2) (L) (R) (X):将(L)到(R)这个区间里的数都(XOR)上(X)。
Input
第一行两个整数(N)和(Q),意义见题目。
接下来(Q)行,每行第一个数(T1=1) (OR) (T1=2),(T1=1)时,接下来(3)个数(L),(R),(X),否则两个数(L),(R)。
Output
对于每个操作(2)一行。
Sample Input
5 8
4 10 3 13 7
1 2 4
2 1 3 3
1 2 4
1 3 3
2 2 5 5
1 1 5
2 1 2 10
1 2 3
Sample Output
26
22
0
34
11
Data Constraint
对于(30)%的数据:(1<=N),(M<=3000)
对于另外(20)%的数据:数据为纯随机数据。
对于(100)%的数据:(1<=N<=100000),(1<=M<=50000),(1<=A[i]),(X<=10^6)
Solution
我们观察,每个数都小于(10^6),我们把它变成二进制,拆成(20)位,对于每一位都开一个线段树
比如,第(1)棵线段树的区间([l,r])我们保存从(a[l])到(a[r])中的每个数的二进制的第(1)位的(0),(1)的个数
求和时,当前第(k)位,我们算出当前有a个(1),b个(0),然后把(ans+=a*2^(k-1))
对于(pushdown),如果修改的数为(x),当前为(k)位,令(h)为(x)的第(k)位,则
如果(h=0),我们不需要修改子树(因为(0)$0=1$,$1$(0=1),相当于没有变过)
如果(h=1),我们只需要交换当前节点的保存的(0)的个数和(1)的个数,并下传标记(因为(0)$1=1$,$1$(1=0),相当于所有的(0)都变成了(1),所有的(1)都变成了(0))
Code
不想写了,CV一下题解代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ls (t<<1)
#define rs ((t<<1)+1)
#define mid ((l+r)>>1)
using namespace std;
int i,j,m,n,p,k,l,r,x,kth;
struct Node{int sum,add;}Tree[32][400001];
int b[32];
void down(int Now,int t,int m)
{ if (!Tree[Now][t].add) return;
Tree[Now][ls].sum=(m-(m>>1))-Tree[Now][ls].sum;
Tree[Now][rs].sum=(m>>1)-Tree[Now][rs].sum;
Tree[Now][ls].add=(Tree[Now][ls].add+1)%2;
Tree[Now][rs].add=(Tree[Now][rs].add+1)%2;
Tree[Now][t].add=0;
}
void change(int ll,int rr,int l,int r,int t,int Now)
{ if (ll<=l&&r<=rr) { Tree[Now][t].sum=(r-l+1)-Tree[Now][t].sum;
Tree[Now][t].add=(Tree[Now][t].add+1)%2; return;}
down(Now,t,r-l+1);
if (ll<=mid) change(ll,rr,l,mid,ls,Now);
if (rr>mid) change(ll,rr,mid+1,r,rs,Now);
Tree[Now][t].sum=(Tree[Now][ls].sum+Tree[Now][rs].sum);
}
void update(int ll,int l,int r,int t,int Now)
{ if (l==r) { Tree[Now][t].sum++; return; }
if (ll<=mid) update(ll,l,mid,ls,Now);
else update(ll,mid+1,r,rs,Now);
Tree[Now][t].sum=(Tree[Now][ls].sum+Tree[Now][rs].sum);
}
void Query(int ll,int rr,int l,int r,int t,int Now)
{ if (ll<=l&&r<=rr) { kth+=Tree[Now][t].sum; return; }
down(Now,t,r-l+1);
if (ll<=mid) Query(ll,rr,l,mid,ls,Now);
if (rr>mid) Query(ll,rr,mid+1,r,rs,Now);
}
void ask(int l,int r)
{ int sum=1,i; long long ans=0;
for (i=1;i<=30;i++)
{ kth=0; Query(l,r,1,n,1,i); ans=(ans+1ll*kth*sum);
sum*=2;
}
printf("%lld
",ans);
}
int main()
{ freopen("pc.in","r",stdin);
freopen("pc.out","w",stdout);
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
{ scanf("%d",&p); k=0;
for (;p;p>>=1)
{++k; if (p&1) update(i,1,n,1,k); }
}
for (i=1;i<=m;i++)
{ scanf("%d",&p);
if (p==1) { scanf("%d%d",&l,&r); ask(l,r); }
else { scanf("%d%d%d",&l,&r,&x); k=0;
for (;x;x>>=1)
{ ++k; if (x&1) change(l,r,1,n,1,k); }
}
}
}