題意:
給定一個序列,給定兩種操作:
-
將一個區間異或上一個給定的值。
-
給定 \(l,r\) 求
\[{\large (\sum_{i=l}^r\bigcup_{j=l}^i A_j) \bmod 2^{30}}
\]
\(0\le a_i,x< 2^{30}\),\(1\le l\le r\le n\)
思路
-
由於運算元以及區間過大,一位一位地去模擬肯定是不行的。因此考慮去離線下來拆位,對於每一個操作的每一位單獨維護貢獻。
-
由於是字首或,因此對於每一位而言,只要有一個數在這一位上是1,那後面的所有值也一定都是1。
因此問題就轉化成了維護區間第一個1所在的位置,答案就是這個位置與右端點的距離。 -
考慮如何去維護這個東西。顯然去查詢不可能直接找,需要去二分。但同時還要維護操作1,因此考慮用線段樹去維護。
那怎麼線上段樹上查詢呢?考慮維護節點所代表的區間是不是全為零,如果全為零的話就向右兒子搜,否則向左兒子搜。
但由於異或操作,還可以維護一個是否全是1方便修改。需要修改的時候將兩個標記交換就可以了。
code
點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
const int p=1073741824;
const int N=2e5+7;
int n,m,a[N],loc;bool s1[N<<2],s2[N<<2],b[N],sign,tag[N<<2];
struct ques
{
int opt,l,r,x;long long ans=0;
}q[N];
#define ls (u<<1)
#define rs ((u<<1)|1)
void push_up(int u)
{
s1[u]=s1[ls]|s1[rs];s2[u]=s2[ls]|s2[rs];
}
void push_down(int u)
{
if(!tag[u]) return;
swap(s1[ls],s2[ls]),swap(s1[rs],s2[rs]);
tag[ls]^=1,tag[rs]^=1;
tag[u]=0;
}
void build(int u,int l,int r)
{
tag[u]=0;if(l==r){s1[u]=b[l],s2[u]=b[l]^1;return;}
int mid=(l+r)>>1;build(ls,l,mid);build(rs,mid+1,r);
push_up(u);
}
void modify(int u,int l,int r,int ql,int qr)
{
if(l>=ql&&r<=qr) {swap(s1[u],s2[u]),tag[u]^=1;return;}
int mid=(l+r)>>1;push_down(u);
if(mid>=ql) modify(ls,l,mid,ql,qr);if(mid<qr) modify(rs,mid+1,r,ql,qr);
push_up(u);
}
void query(int u,int l,int r,int ql,int qr)
{
if((!s1[u])||sign||r<ql||l>qr) return;
if(l==r) {if(s1[u]&&l<loc&&l>=ql)loc=l,sign=1;return;}
int mid=(l+r)>>1;push_down(u);
if(mid>=ql) query(ls,l,mid,ql,qr);
if(sign) return;
if(mid<qr) query(rs,mid+1,r,ql,qr);
}
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) {cin>>q[i].opt>>q[i].l>>q[i].r;if(q[i].opt==1) cin>>q[i].x;}
for(int k=0;k<=30;k++)
{
for(int i=1;i<=n;i++) b[i]=(a[i]>>k)&1;build(1,1,n);
for(int i=1;i<=m;i++)
{
if(q[i].opt==1) {if(((q[i].x>>k)&1)==1) modify(1,1,n,q[i].l,q[i].r);}
else
{
sign=0;loc=q[i].r+1;query(1,1,n,q[i].l,q[i].r);
q[i].ans=(q[i].ans+1ll*(q[i].r-loc+1ll)*(1ll<<k)%p)%p;
}
}
}
for(int i=1;i<=m;i++) if(q[i].opt==2) cout<<q[i].ans<<'\n';
return 0;
}