题目
描述
有(m)个操作一次发生,每个操作有(frac{1}{2})的概率被执行 ;
一次操作为线段树([1,n])上的 (modify(Node,l,r,ql,qr)) ;
询问所有(2^m)情况的懒标记之和;
范围
(1 le n le m le 10^5)
题解
-
直接求比较麻烦,考虑求出m个操作之后每个节点有懒标记的概率,再乘以 $ 2^m $ ;
-
void update(int k,int l,int r,int x,int y){ if(l==x&&r==u){...; return;} //1 //4 int mid=l+r>>1; pushdown(k); //2 if(y<=mid)update(ls,l,mid,x,y); //3 else if(x>mid)update(rs,mid+1,r,x,y); //3 else update(ls,l,mid,x,mid),update(rs,mid+1,r,mid+1,y); //1 }
-
如代码,可以把区间分成四类来讨论:
1.经过但不为终止节点的区间;
2.为终止节点的区间;
3.经过路径节点的被psd到的兄弟节点;
4.在终止节点的子树里面的点;
5.没有经过的节点;
-
只需要维护(f)表示标记个数的概率,(g)表示到根的路径上有标记的概率,只需要写个线段树跟着维护就可以了;
-
为什么这么套路的东西我都没有想出来???
#include<bits/stdc++.h> #define mod 998244353 #define ll long long #define ls (k<<1) #define rs (k<<1|1) using namespace std; const int N=100010; int n,m,f[N<<3],g[N<<3],s[N<<3],ly1[N<<3],ly2[N<<3],iv2=mod+1>>1; char gc(){ static char*p1,*p2,s[1000000]; if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin); return(p1==p2)?EOF:*p1++; } int rd(){ int x=0;char c=gc(); while(c<'0'||c>'9')c=gc(); while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc(); return x; } void build(int k,int l,int r){ ly1[k]=1;ly2[k]=s[k]=f[k]=g[k]=0; if(l==r)return ; int mid=l+r>>1; build(ls,l,mid); build(rs,mid+1,r); } void mfy(int k,int x,int y){ g[k]=((ll)g[k]*x%mod+y)%mod; ly1[k]=(ll)ly1[k]*x%mod; ly2[k]=((ll)ly2[k]*x%mod+y)%mod; } void pushup(int k){s[k]=((ll)s[ls]+s[rs]+f[k])%mod;} void pushdown(int k){ mfy(ls,ly1[k],ly2[k]); mfy(rs,ly1[k],ly2[k]); ly1[k]=1;ly2[k]=0; } void update(int k,int l,int r,int x,int y){ if(l==x&&r==y){ f[k]=(ll)(f[k]+1)*iv2%mod; mfy(k,iv2,iv2); // pushdown(k); pushup(k); return; } pushdown(k); f[k]=(ll)f[k]*iv2%mod; g[k]=(ll)g[k]*iv2%mod; int mid=l+r>>1; if(y<=mid)f[rs]=(ll)(f[rs]+g[rs])*iv2%mod,pushup(rs),update(ls,l,mid,x,y); else if(x>mid)f[ls]=(ll)(f[ls]+g[ls])*iv2%mod,pushup(ls),update(rs,mid+1,r,x,y); else update(ls,l,mid,x,mid),update(rs,mid+1,r,mid+1,y); pushup(k); } int main(){ // freopen("segment.in","r",stdin); // freopen("segment.out","w",stdout); n=rd();m=rd(); build(1,1,n); for(int i=1,pw=1;i<=m;++i){ int op=rd(),l,r; if(op&1)l=rd(),r=rd(),update(1,1,n,l,r),pw=(pw<<1)%mod; else printf("%d ",(ll)s[1]*pw%mod); } return 0; }