[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;
}
相关文章
相关标签/搜索