[ZJOI2019]線段樹(線段樹)

[ZJOI2019]線段樹(線段樹)

題面

洛谷ios

題解

首先問題等價於前面每次操做均可能進行修改或者不修改,求全部狀況下有標記點的個數。 考慮依次修改操做會產生的影響,把線段樹節點進行分類。ui

  • 這個點和以及其父親都和修改區間無交:顯然這個點的標記不會被修改。
  • 這個點和修改區間無交但父親和修改區間有交:那麼這個區間有沒有標記只和自己有沒有標記以及是否存在一個祖先有標記相關。
  • 這個點被修改區間徹底包含,且父親沒有被徹底包含:顯然這個點就是放置標記的一個點,那麼必定會有標記。
  • 這個點被修改區間徹底包含,且父親節點也被徹底包含:那麼這個點的標記不會變化。
  • 這個點和修改區間有交但沒有被徹底包含:那麼這個點必定會$pushdown$,一定不會有標記。

其中四類點的標記狀態都和其餘點無關,只有第二類標記和其到根節點的全部節點相關。 那麼顯然記錄兩個狀態就行了,即這個點被標記的機率以及這個點到根節點至少有一個點被標記的機率,不妨記爲$f,g$。 考慮如何轉移:spa

  • 第一類點:顯然沒有變化。
  • 第二類點:首先$0.5$的機率不會變化,而後$0.5$的機率變成$g$,那麼轉移就是$f=0.5f'+0.5*g'$;而後考慮$g$的轉移,仍是$0.5$的機率不變化,$0.5$的機率變成$g'$,因此轉移是$g=0.5g'+0.5g'=g'$。
  • 第三類點:$f=0.5f'+0.5$;$g=0.5g'+0.5$。
  • 第四類點:$f$不會變化,$g$會變成$0.5g'+0.5$。
  • 第五類點:$f=0.5f',g=0.5g'$。

第四類點彷佛須要資磁區間乘法和區間加法,不過這個東西仍是個線段樹模板。code

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 100100
#define MOD 998244353
#define inv2 499122177
#define lson (now<<1)
#define rson (now<<1|1)
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n,m,pw=1,f[MAX<<3],g[MAX<<3],mul[MAX<<3],pls[MAX<<3],s[MAX<<3];
void Build(int now,int l,int r)
{
	mul[now]=1;if(l==r)return;
	int mid=(l+r)>>1;
	Build(lson,l,mid);Build(rson,mid+1,r);
}
void pushup(int now){s[now]=((s[lson]+s[rson])%MOD+f[now])%MOD;}
void upd(int now){f[now]=1ll*inv2*(f[now]+g[now])%MOD;pushup(now);}
void puttag(int now,int m,int p)
{
	g[now]=(1ll*g[now]*m+p)%MOD;
	mul[now]=1ll*mul[now]*m%MOD;
	pls[now]=(1ll*pls[now]*m+p)%MOD;
}
void pushdown(int now)
{
	if(mul[now]==1&&pls[now]==0)return;
	puttag(lson,mul[now],pls[now]);
	puttag(rson,mul[now],pls[now]);
	mul[now]=1;pls[now]=0;
}
void Modify(int now,int l,int r,int L,int R)
{
	if(L==l&&r==R)
	{
		f[now]=1ll*inv2*(f[now]+1)%MOD;
		puttag(now,inv2,inv2);pushup(now);return;
	}
	int mid=(l+r)>>1;pushdown(now);
	f[now]=1ll*inv2*f[now]%MOD;
	g[now]=1ll*inv2*g[now]%MOD;
	if(R<=mid)Modify(lson,l,mid,L,R),upd(rson);
	else if(L>mid)Modify(rson,mid+1,r,L,R),upd(lson);
	else Modify(lson,l,mid,L,mid),Modify(rson,mid+1,r,mid+1,R);
	pushup(now);
}
int main()
{
	n=read();m=read();
	while(m--)
	{
		int opt=read(),l,r;
		if(opt==1)l=read(),r=read(),Modify(1,1,n,l,r),pw=(pw+pw)%MOD;
		else printf("%lld\n",1ll*pw*s[1]%MOD);
	}
	return 0;
}
相關文章
相關標籤/搜索