P11071 「QMSOI R1」 Distorted Fate
题目链接
简要题意:
给定一个长度为 \(n\) 的数组 \(A\),你需要完成以下 \(q\) 次操作。
-
1 l r x
将 \(A_i(l\le i\le r)\) 异或上 \(x\)。 -
2 l r
求:
\[(\sum_{i=l}^r\bigcup_{j=l}^i A_j) \bmod 2^{30}
\]
其中 \(\bigcup\) 表示按位或。
区间异或,查询区间每个前缀的按位或之和的和
主要算法:
按位计算,线段树,优化空间。
思路:
- 因为是二进制相关的计数,所以自然想到拆位来做。
- 拆完位之后,区间异或就是0,1翻转,统计答案就是找到 \(l\) 到 \(r\) 中第一个一所在的位置。只有0,1,所以线段树维护一的个数即可。
#include <bits/stdc++.h>
using namespace std;
const int mod=(1<<30),N=2e5+10;
#define int long long//注意long long
int n,q,a[N];
long long ans[N];
struct node
{
int opt,l,r,x;
}qq[N];
struct stu
{
int sum,tag;
}sh[N<<2];
inline void build(int x,int l,int r,int k)
{
sh[x].tag=0;//全部清空
if(l==r)
{
if((a[l]>>k)&1)sh[x].sum=1;
else sh[x].sum=0;
sh[x].tag=0;
return ;
}
int mid=(l+r)>>1;
build(x<<1,l,mid,k);build(x<<1|1,mid+1,r,k);
sh[x].sum=sh[x<<1].sum+sh[x<<1|1].sum;
return ;
}
void pushdown(int x,int l,int r)
{
if(sh[x].tag==0)return;
int mid=(l+r)>>1;
sh[x<<1].sum=(mid-l+1)-sh[x<<1].sum;
sh[x<<1].tag^=1;
sh[x<<1|1].sum=(r-mid)-sh[x<<1|1].sum;
sh[x<<1|1].tag^=1;
sh[x].tag=0;
}
inline void modify(int x,int l,int r,int lt,int rt,int zhi)
{
if(zhi==0)return;
if(l>rt||r<lt)return;
if(lt<=l&&rt>=r)
{
sh[x].sum=(r-l+1)-sh[x].sum;
sh[x].tag^=1;
return ;
}
pushdown(x,l,r);
int mid=(l+r)>>1;
if(lt<=mid)modify(x<<1,l,mid,lt,rt,zhi);
if(rt>mid)modify(x<<1|1,mid+1,r,lt,rt,zhi);
sh[x].sum=sh[x<<1].sum+sh[x<<1|1].sum;
return ;
}
inline int query(int x,int l,int r)
{
if(!sh[x].sum)return -1;
if(l==r) return sh[x].sum?l:-1;
pushdown(x,l,r);
int mid=(l+r)>>1;
int q2=query(x<<1,l,mid);
if(q2!=-1)return q2;
q2=query(x<<1|1,mid+1,r);
if(q2!=-1)return q2;
return -1;
}//不能只写这一部分,不然找的就是全局最大。
inline int query2(int x,int l,int r,int lt,int rt)
{
if(lt<=l&&rt>=r)
{
int q2=query(x,l,r);
if(q2!=-1)return q2;
else return -1;
}
int mid=(l+r)>>1,q2=-1;
pushdown(x,l,r);
if(lt<=mid)q2=query2(x<<1,l,mid,lt,rt);
if(q2!=-1)return q2;
if(rt>mid)q2=query2(x<<1|1,mid+1,r,lt,rt);
if(q2!=-1)return q2;
return -1;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>q;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=q;i++)
{
cin>>qq[i].opt>>qq[i].l>>qq[i].r;
if(qq[i].opt==1)
cin>>qq[i].x;
}
long long anw;
for(int i=0,anw=1;i<=30;i++,anw*=2)
{
build(1,1,n,i);
for(int j=1;j<=q;j++)//注意i,j
{
if(qq[j].opt==1)
modify(1,1,n,qq[j].l,qq[j].r,(qq[j].x>>i)&1);//右移左移要注意
else
{
int q2=query2(1,1,n,qq[j].l,qq[j].r);
if(q2!=-1)
ans[j]=(ans[j]+anw*(qq[j].r-q2+1)%mod)%mod;
}
}
}
for(int i=1;i<=q;i++)
{
if(qq[i].opt==2)cout<<ans[i]<<'\n';
}
return 0;
}