洛谷ios
首先問題等價於前面每次操做均可能進行修改或者不修改,求全部狀況下有標記點的個數。 考慮依次修改操做會產生的影響,把線段樹節點進行分類。ui
其中四類點的標記狀態都和其餘點無關,只有第二類標記和其到根節點的全部節點相關。 那麼顯然記錄兩個狀態就行了,即這個點被標記的機率以及這個點到根節點至少有一個點被標記的機率,不妨記爲$f,g$。 考慮如何轉移:spa
第四類點彷佛須要資磁區間乘法和區間加法,不過這個東西仍是個線段樹模板。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; }