[9.26模拟赛]T3
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\n",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); }
}
}
}