• Luogu5280 ZJOI2019线段树(线段树)


      容易发现相当于求2m种操作序列所得的每种线段树tag数量之和。显然考虑每个点的贡献,也即有多少种方案会使该点上有tag。可以将点分为四类:

      1.修改时被经过且有儿子被修改的节点

      2.修改时被经过且没有儿子被修改的节点

      3.修改时未被经过且有兄弟被修改的节点

      4.修改时未被经过且没有兄弟被修改的节点 

      考虑一次修改对这些点的影响。设该次操作之前已进行p次修改。易得:

      1.方案数不变

      2.方案数+2p

      3.方案数+修改前该点到根路径(包括该点自身)上有tag的方案数

      4.方案数*2

      只要考虑维护3类点所需的东西即可。对此易得:

      1.方案数不变

      2.方案数+2p

      3.方案数*2

      4.与其最近的非4类点祖先相同

      维护两棵线段树即可。其中第一棵可以转化为维护概率来避免打lazy标记,当然并不重要。

      注意维护3类点取出方案数时需要pushdown,并且对此处的pushdown需要小心是否有写丑导致四倍空间不够用。

      upd:上一句可以划掉,突然发现自己莫名其妙的把一个log硬是写成两个log了……两棵线段树看成一棵完全没问题,顺便pushdown一下就好。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define P 998244353
    #define N 100010
    #define inv 499122177
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,m,tree[N<<2],p[N],p2[N],stk[N],ans;
    int val[N<<2],taga[N<<2],tagm[N<<2];
    void del(int x){ans=(ans+P-x)%P;}
    void ins(int x){ans=(ans+x)%P;}
    void updatea(int k,int x)
    {
        val[k]=(val[k]+x)%P;
        taga[k]=(taga[k]+x)%P;
    }
    void downa(int k)
    {
        updatea(k<<1,taga[k]);
        updatea(k<<1|1,taga[k]);
        taga[k]=0;
    }
    void updatem(int k,int x)
    {
        val[k]=1ll*val[k]*x%P;
        tagm[k]=1ll*tagm[k]*x%P;
        taga[k]=1ll*taga[k]*x%P;
    }
    void downm(int k)
    {
        updatem(k<<1,tagm[k]);
        updatem(k<<1|1,tagm[k]);
        tagm[k]=1;
    }
    void add(int k,int l,int r,int x,int y,int p)
    {
        if (l==x&&r==y) {updatea(k,p);return;}
        if (tagm[k]!=1) downm(k);
        if (taga[k]!=0) downa(k);
        int mid=l+r>>1;
        if (y<=mid) 
        {
            updatem(k<<1|1,2);
            add(k<<1,l,mid,x,y,p);
        }
        else if (x>mid)
        {
            updatem(k<<1,2);
            add(k<<1|1,mid+1,r,x,y,p);
        }
        else add(k<<1,l,mid,x,mid,p),add(k<<1|1,mid+1,r,mid+1,y,p);
    }
    int query(int k)
    {
        int top=0;
        for (int i=k;i;i>>=1) stk[++top]=i;
        for (int i=top;i>1;i--)
        {
            if (tagm[stk[i]]!=1) downm(stk[i]);
            if (taga[stk[i]]!=0) downa(stk[i]);
        }
        return val[k];
    }
    void modify(int k,int l,int r,int x,int y,int p)
    {
        if (l==x&&r==y)
        {
            del(tree[k]);
            tree[k]=1ll*(tree[k]+1)*inv%P;
            ins(tree[k]);
            return;
        }
        if (tagm[k]!=1) downm(k);
        if (taga[k]!=0) downa(k);
        del(tree[k]);
        tree[k]=1ll*tree[k]*inv%P;
        ins(tree[k]);
        int mid=l+r>>1;
        if (y<=mid)
        {
            del(tree[k<<1|1]);
            tree[k<<1|1]=1ll*(tree[k<<1|1]+1ll*val[k<<1|1]*p%P)*inv%P;
            ins(tree[k<<1|1]);
            modify(k<<1,l,mid,x,y,p);
        }
        else if (x>mid)
        {
            del(tree[k<<1]);
            tree[k<<1]=1ll*(tree[k<<1]+1ll*val[k<<1]*p%P)*inv%P;
            ins(tree[k<<1]);
            modify(k<<1|1,mid+1,r,x,y,p);
        }
        else modify(k<<1,l,mid,x,mid,p),modify(k<<1|1,mid+1,r,mid+1,y,p);
    }
    void fill(int k,int l,int r){tagm[k]=1;if (l==r) return;fill(k<<1,l,l+r>>1);fill(k<<1|1,(l+r>>1)+1,r);}
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read();
        p[0]=1;for (int i=1;i<=m;i++) p[i]=(p[i-1]<<1)%P;
        p2[0]=1;for (int i=1;i<=m;i++) p2[i]=1ll*p2[i-1]*inv%P;
        int cnt=0;fill(1,1,n);
        for (int _=1;_<=m;_++)
        {
            int op=read();
            if (op==1)
            {
                int l=read(),r=read();
                modify(1,1,n,l,r,p2[cnt]);
                add(1,1,n,l,r,p[cnt]);
                cnt++;
            }
            else printf("%d
    ",1ll*ans*p[cnt]%P);
        }
        return 0;
    }
    

      

  • 相关阅读:
    静态库,动态库
    vim
    消息队列-Rabbitmq处理消息及在Spring中的应用
    消息队列 -- 队列(Queue)和主题(Topic)
    Sing的签名算法
    Jquery
    VUE
    node
    vue 加载静态图片
    vue :style 动态绑定style
  • 原文地址:https://www.cnblogs.com/Gloid/p/10646414.html
Copyright © 2020-2023  润新知