【LOJ3043】「ZJOI2019」線段樹
阿新 • • 發佈:2019-04-22
https lse 當前 row clas 標記 int push ret ,其所有子節點(包括自己) \(g_j \leftarrow \frac{g_j+1}{2}\) ; 否則因為當前到達的區間標記已被下傳,所以 \(f_i\leftarrow \frac{f_i}{2}, g_i\leftarrow \frac{g_i}{2}\) 。 線段樹維護 \(f_i,g_i\) , \(g_i\) 的維護需要打標記。
題面
問題可以轉化為每次區間覆蓋操作有 \(\frac{1}{2}\) 的概率進行,求標記和的期望。於是我們只要求出所有點有標記的概率即可。
我們設 \(f_i\) 表示節點 \(i\) 有標記的概率, \(g_i\) 表示節點 \(i\) 的祖先節點有標記的概率。如果一個節點未完全被包含,那麽其未被包含的節點是否有標記取決於其祖先節點是否有標記,故要用來自祖先節點的信息來更新答案(設未包含的節點為 \(j\) ,那麽 \(f_j \leftarrow \frac{f_j+g_j}{2}\) )。如果一個節點被完全包含,那麽 \(f_i \leftarrow \frac{f_i+1}{2}\)
#include<cstdio> #include<cassert> inline int gi() { char c=getchar(); int x=0; for(;c<'0'||c>'9';c=getchar()); for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0'; return x; } const int N=2e5+5,Mod=998244353,inv=Mod+1>>1; int n,m,f[N<<2],g[N<<2],sum[N<<2],tg1[N<<2],tg2[N<<2],fm=1; #define lx (x<<1) #define rx (x<<1|1) #define mul(x,y) (1ll*(x)*(y)%Mod) #define div2(x) (1ll*(x)*inv%Mod) void pushdown(int x) { if(tg1[x]==1&&tg2[x]==0) return ; tg1[lx]=mul(tg1[lx],tg1[x]),tg1[rx]=mul(tg1[rx],tg1[x]); tg2[lx]=(mul(tg2[lx],tg1[x])+tg2[x])%Mod; tg2[rx]=(mul(tg2[rx],tg1[x])+tg2[x])%Mod; g[lx]=(mul(g[lx],tg1[x])+tg2[x])%Mod; g[rx]=(mul(g[rx],tg1[x])+tg2[x])%Mod; tg1[x]=1,tg2[x]=0; } void solve(int x) { f[x]=div2((f[x]+g[x])%Mod); sum[x]=((sum[lx]+sum[rx])%Mod+f[x])%Mod; } void update(int x, int l, int r, int sl, int sr) { if(sl<=l&&r<=sr) { f[x]=div2(f[x]+1); g[x]=div2(g[x]+1); sum[x]=((sum[lx]+sum[rx])%Mod+f[x])%Mod; tg1[x]=div2(tg1[x])%Mod; tg2[x]=(div2(tg2[x])+inv)%Mod; return ; } pushdown(x); f[x]=div2(f[x]),g[x]=div2(g[x]); int mid=l+r>>1; if(sl>mid) update(rx,mid+1,r,sl,sr),solve(lx); else if(sr<=mid) update(lx,l,mid,sl,sr),solve(rx); else update(lx,l,mid,sl,sr),update(rx,mid+1,r,sl,sr); sum[x]=((sum[lx]+sum[rx])%Mod+f[x])%Mod; } int main() { n=gi(),m=gi(); for(int i=1;i<=(n<<2);++i) tg1[i]=1; while(m--) { int op=gi(); if(op==2) printf("%d\n",1ll*fm*sum[1]%Mod); else { fm=2ll*fm%Mod; int l=gi(),r=gi(); update(1,1,n,l,r); } } }
【LOJ3043】「ZJOI2019」線段樹