• [ZJOI2019]线段树(线段树)


    看到这题,首先想到将求和转期望,即每次操作进行概率为1/2,求节点打标记概率。

    首先对于每次区间修改操作,对节点进行分类:

    1、这个点和其父亲都和修改区间无交,这种情况可以无视。

    2、这个点和修改区间无交但父亲和修改区间有交,这样该区间有无标记只和本身及是否存在一个祖先有标记相关。

    3、这个点被修改区间覆盖,且父节点也被覆盖,则无变化。

    4、这个点和修改区间有交但没有被完全包含,则不会有标记(因为要pushdown)。

    然后记录该节点有标记的概率f,和祖先至少有一个有标记的概率g,然后根据上面表述的意思转移即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    const int N=2e5+7,mod=998244353,inv2=499122177;
    int n,m,pw[N],inv[N],f[N<<2],g[N<<2],s[N<<2],tag[N<<2];
    void pushup(int rt){s[rt]=(1ll*s[rt<<1]+s[rt<<1|1]+f[rt])%mod;}
    void modify(int rt,int v){g[rt]=1ll*(g[rt]+pw[v]-1)*inv[v]%mod,tag[rt]+=v;}
    void pushdown(int rt)
    {
        if(!tag[rt])return;
        modify(rt<<1,tag[rt]),modify(rt<<1|1,tag[rt]);
        tag[rt]=0;
    }
    void update(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            tag[rt]++,f[rt]=1ll*(f[rt]+1)*inv2%mod,g[rt]=1ll*(g[rt]+1)*inv2%mod;
            pushup(rt);return;
        }
        if(L>r||R<l)
        {
            f[rt]=1ll*(f[rt]+g[rt])*inv2%mod;
            pushup(rt);return;
        }
        pushdown(rt);
        int mid=l+r>>1;
        f[rt]=1ll*f[rt]*inv2%mod,g[rt]=1ll*g[rt]*inv2%mod;
        update(L,R,lson),update(L,R,rson);
        pushup(rt);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        pw[0]=inv[0]=1;for(int i=1;i<=n;i++)pw[i]=2ll*pw[i-1]%mod,inv[i]=1ll*inv[i-1]*inv2%mod;
        int num=1;
        while(m--)
        {
            int op,l,r;scanf("%d",&op);
            if(op==2)printf("%d
    ",1ll*s[1]*num%mod);
            else scanf("%d%d",&l,&r),num=2ll*num%mod,update(l,r,1,n,1);
        }
    }
    View Code
  • 相关阅读:
    微信小程序学习随笔
    SqlServer索引假脱机的解决
    web服务器出现大量CLOSE_WAIT连接的前因后果
    SqlServer和mysql字段拼接方法
    使用beego创建员工加班调休系统
    在c#程序中初步使用redis
    使用golang实现批量发送面试邀请邮件
    记c# rabbitmq的使用
    项目中使用mongodb的尝试
    手机集成支付宝支付功能的注意事项
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/10791669.html
Copyright © 2020-2023  润新知