[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); }
      }
      }
}
posted @ 2019-09-29 13:43  Agakiss  阅读(149)  评论(0编辑  收藏  举报