P11071 「QMSOI R1」 Distorted Fate題解

all_for_god發表於2024-11-13

題意:
給定一個序列,給定兩種操作:

  1. 將一個區間異或上一個給定的值。

  2. 給定 \(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;
}

相關文章