1. 程式人生 > >●洛谷P3688 [ZJOI2017]樹狀數組

●洛谷P3688 [ZJOI2017]樹狀數組

特殊情況 clu body 函數 tar == 樹狀 -s zjoi

題鏈:

https://www.luogu.org/problemnew/show/P3688
題解:

二維線段樹。

先不看詢問時l=1的特殊情況。


對於一個詢問(l,r),如果要讓錯誤的程序得到正確答案,
顯然應該滿足l-1位置的值=r位置的值(或者說兩個位置的異或值為0)。
那麽定義二元組函數f(x,y)表示x位置與y位置的異或值為0的概率
如果可以維護出所有這樣的二元組的函數值,
對於一個詢問的話,就可以很方便的回答了。
現在看看,怎樣維護這樣的二元組的函數值。
假設現在給出了一個操作1:(L,R),(令prob=1/len)
那麽顯然,對於如下這些二元組:(0~L-1,L~R)和(L~R,R+1~N),


它們的函數值都會乘上(1-prob),因為有(1-prob)的概率無法使得其異或值改變。
再對於這些二元組(L~R,L~R),它們的函數值都會乘上(1-2*prob)。
把上面的二元組看出平面上的點,那麽每個操作1就對應著改變平面上若幹個矩形的值。
所以就直接使用二維線段樹(樹套樹)去維護二維區間修改+單點查詢

至於詢問中l=1的情況,如果要讓錯誤程序得到正確答案,那麽[1~r-1]這一段的異或和就應該等於[r+1~N]這一段的異或和。
這裏有這麽一種做法:
記錄到當前詢問位置,之前有了cnt個1操作。
然後二維線段樹查詢f(0,r)的得到prob,
由於0位置不可能被隨機到1操作,
所以prob就表示r位置被之前的所有1操作弄成0的概率,(即有偶數個1操作隨機到了r位置的概率)。

如果cnt為偶數,那麽一定[1~r-1]這一段和[r+1~N]這一段被1操作隨機到的奇偶性相同,
也就是說[1~r-1]這一段的異或和就應該等於[r+1~N]這一段的異或和,所以答案就是prob.

反之,如果cnt為奇數,(1-prob)表示r位置被之前的所有1操作弄成1的概率,(即有奇數個1操作隨機到了r位置的概率)。
這樣的話那麽也一定[1~r-1]這一段和[r+1~N]這一段被1操作隨機到的奇偶性相同,
也就是說[1~r-1]這一段的異或和就應該等於[r+1~N]這一段的異或和,所以答案就是(1-prob).


代碼:

#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;
const int MOD=998244353;
int N,M,cnt;
int merge(int p1,int p2){
	return (1ll*p1*p2+1ll*(1-p1+MOD)*(1-p2+MOD))%MOD;
}
struct SGT2{
	int size;
	int ls[MAXN*200],rs[MAXN*200],p[MAXN*200];
	void Modify(int &u,int l,int r,int yl,int yr,int prob){
		if(!u) u=++size,p[u]=1;
		if(yl<=l&&r<=yr) return (void)(p[u]=merge(p[u],prob));
		int mid=(l+r)>>1;
		if(yl<=mid) Modify(ls[u],l,mid,yl,yr,prob);
		if(mid<yr) Modify(rs[u],mid+1,r,yl,yr,prob);
	}
	int Query(int u,int l,int r,int py){
		if(!u) return 1;
		int ret=merge(1,p[u]);
		if(l==r) return ret;
		int mid=(l+r)>>1;
		if(py<=mid) ret=merge(ret,Query(ls[u],l,mid,py));
		else ret=merge(ret,Query(rs[u],mid+1,r,py));
		return ret;
	}
}DTy;
struct SGT1{
	int size,root;
	int ls[MAXN*2],rs[MAXN*2],yroot[MAXN*2];
	void Modify(int &u,int l,int r,int xl,int xr,int yl,int yr,int prob){
		if(!u) u=++size;
		if(xl<=l&&r<=xr) return DTy.Modify(yroot[u],0,N+1,yl,yr,prob);
		int mid=(l+r)>>1;
		if(xl<=mid) Modify(ls[u],l,mid,xl,xr,yl,yr,prob);
		if(mid<xr) Modify(rs[u],mid+1,r,xl,xr,yl,yr,prob);
	}
	int Query(int u,int l,int r,int px,int py){
		if(!u) return 1;
		int ret=merge(1,DTy.Query(yroot[u],0,N+1,py));
		if(l==r) return ret;
		int mid=(l+r)>>1;
		if(px<=mid) ret=merge(ret,Query(ls[u],l,mid,px,py));
		else ret=merge(ret,Query(rs[u],mid+1,r,px,py));
		return ret;
	}
}DTx;
int fastpow(int a,int b){
	int ret=1;
	for(;b;a=1ll*a*a%MOD,b>>=1)
		if(b&1) ret=1ll*ret*a%MOD;
	return ret;
}
int main(){
	//cout<<fastpow(3,MOD-2)<<endl;
	scanf("%d%d",&N,&M);
	int t,l,r,prob,ans;
	for(int i=1;i<=M;i++){
		scanf("%d%d%d",&t,&l,&r);
		if(t==1){
			cnt++;
			prob=fastpow(r-l+1,MOD-2);
			DTx.Modify(DTx.root,0,N+1,0,l-1,l,r,(1ll-prob+MOD)%MOD);
			DTx.Modify(DTx.root,0,N+1,l,r,r+1,N+1,(1ll-prob+MOD)%MOD);
			if(r-l+1>=2) DTx.Modify(DTx.root,0,N+1,l,r,l,r,(1ll-2ll*prob+2ll*MOD)%MOD);
		}
		else{
			l--;
			ans=DTx.Query(DTx.root,0,N+1,l,r);
			if(l==0){
				if((cnt&1)==0) printf("%d\n",ans);
				else printf("%d\n",(1-ans+MOD)%MOD);
			}
			else printf("%d\n",ans);
		}
	}
	return 0;
}

  

●洛谷P3688 [ZJOI2017]樹狀數組