• [ZJOI2019] 线段树


    一、题目

    点此看题

    二、解法

    考虑修改操作对每个点的影响,我们可以按照与修改区间的关系把点分类(相交,包含,相离),在此基础上,包含或相离节点的状态还与其父亲有关系,所以它们还要按照父亲的状态再次分类。

    具体可以分为一下五类:

    • 与修改区间相交,但不包含在修改区间内部的节点。
    • 包含在修改区间内部,但其父亲不存在或者不包含在修改区间内部。
    • 与修改区间相离,但是其父亲与修改区间相交。
    • 包含在修改区间内部,其父亲也包含在修改区间内部。
    • 与修改区间相离,其父亲也与修改区间相离。

    分析影响:

    • 对于第一类节点,操作后无标记。
    • 对于第二类节点,操作后有标记。
    • 对于第三类节点,有无标记取决于这个节点到根的链上是否有标记。
    • 对于第四类和第五类节点,操作无影响。

    \(f[u]\) 表示 \(u\) 有标记的占比,\(g[u]\) 表示 \(u\) 的链上有标记的占比:

    • 对于第一类节点,一半保持原样,另一半无标记,\((f[u],g[u])=(\frac{1}{2}f[u],\frac{1}{2}g[u])\)
    • 对于第二类节点,一半保持原样,另一半有标记,\((f[u],g[u])=(\frac{1}{2}f[u]+\frac{1}{2},\frac{1}{2}g[u]+\frac{1}{2})\)
    • 对于第三类节点,一半保持原样,另一半取决于 \(u\) 到根的路径,\((f[u],g[u])=(\frac{1}{2}f[u]+\frac{1}{2}g[u],g[u])\)
    • 对于第四类节点,一半保持原样,另一半点 \(u\) 不受影响,但是到根路径一定有标记:\((f[u],g[u])=(f[u],\frac{1}{2}g[u]+\frac{1}{2})\)
    • 对于第五类节点,一半保持原样,另一半也不受影响:\((f[u],g[u])=(f[u],g[u])\)

    前三类的节点数都是 \(O(\log n)\) 的,后两类的节点数是 \(O(n)\) 的,所以必须以打标记的方式维护第四类节点。

    时间复杂度 \(O(n\log n)\)

    #include <cstdio>
    #include <iostream>
    using namespace std;
    const int M = 400005;
    #define int long long
    const int MOD = 998244353;
    const int inv = (MOD+1)/2;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,p,fl[M],f[M],g[M],s[M];
    void work(int i,int c)
    {
        g[i]=(g[i]*c+1-c+MOD)%MOD;
        fl[i]=fl[i]*c%MOD;
    }
    void upd(int i,int ty)
    {
        s[i]=f[i];
        if(!ty) s[i]=(s[i]+s[i<<1]+s[i<<1|1])%MOD;
    }
    void down(int i)
    {
        if(fl[i]==1) return ;
        work(i<<1,fl[i]);work(i<<1|1,fl[i]);
        fl[i]=1;
    }
    void dfs(int i,int l,int r,int L,int R)
    {
        if(L>r || l>R)//3
        {
            f[i]=(f[i]+g[i])*inv%MOD;
            upd(i,l==r);return ;
        }
        if(L<=l && r<=R)//2
        {
            f[i]=(f[i]+1)*inv%MOD;
            upd(i,l==r);
            work(i,inv);//2&4
            return ;
        }
        int mid=(l+r)>>1;down(i);
        f[i]=f[i]*inv%MOD;//1
        g[i]=g[i]*inv%MOD;
        dfs(i<<1,l,mid,L,R);
        dfs(i<<1|1,mid+1,r,L,R);
        upd(i,0);
    }
    signed main()
    {
        n=read();m=read();p=1;
        for(int i=1;i<=4*n;i++) fl[i]=1;
        while(m--)
        {
            int op=read();
            if(op==1)
            {
                int l=read(),r=read();
                dfs(1,1,n,l,r);
                p=(p+p)%MOD;
            }
            else printf("%lld\n",p*s[1]%MOD);
        }
    }
    
  • 相关阅读:
    个人兴趣与公司业务的关系
    分析能力的8个等级(转)
    DSL应用的优点
    架构师应具备的概要技能
    Cheetah
    不能运行VS2005的DSL Tool例子
    推荐:原型工具GUI Design Studio
    Viewpoints 1.0 for Visual Studio .NET 2008
    原创故事 - 不死鸡和不死牛的故事
    Antlr构建表达式引擎
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/16499692.html
Copyright © 2020-2023  润新知