• 「PKUWC 2018」Minimax


    传送门:Here

    一道线段树合并好题

    如果要维护点$ x$的信息,相当于合并$ x$的两棵子树

    对于这题显然有:任何叶子节点的权值都可能出现在其祖先上

    因而我们只需要在线段树合并的时候维护概率即可

    我们令$ maxa(i)$表示在左子树中权值比i大的概率,$ maxb(i)$表示在右子树中权值比i大的概率,$ pL$表示这个节点选择较大权值为最终结果的概率

    若一个出现在左子树的权值v成为了最终权值,概率应为$ maxb(v)*(1-pL)+(1-maxb(v))*pL)=maxb(v)+pL-2*maxb(v)*pL$

    同理一个出现在右子树的权值v成为最终权值的概率应为$ maxa(v)*(1-pL)+(1-maxa(v))*pL)=maxa(v)+pL-2*maxa(v)*pL$

    直接暴力枚举线段树上所有节点更新权值效率低下,考虑如何在合并过程中完成$ maxa$和$ maxb$的维护

    我们优先合并右子树,即从大到小合并,初始可以认为不存在比自己大的也就是$ maxa=maxb=0$

    合并两棵树的时候由于优先合并右边,可以保证左边均没有被合并过而右边已经合并完全

    这时候$ maxa$和$ maxb$恰好就是对应的函数值,然后更新$ maxa$或$ maxb$的值(加上这段区间里出现的概率)

    同普通线段树合并,如果发现某棵子树为空,则给另一颗子树的所有概率乘上$ maxa$或$ maxb$,以标记形式下传

    最后遍历根节点所对应的线段树求出答案即可

    code:

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define M 300010
    #define rt register int
    #define l putchar('
    ')
    #define ll long long
    #define r read()
    #define p 998244353
    using namespace std;
    inline ll read()
    {
        register ll x = 0; char zf = 1; char ch;
        while (ch != '-' && !isdigit(ch)) ch = getchar();
        if (ch == '-') zf = -1, ch = getchar();
        while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x * zf;
    }int i,j,k,m,n,x,y,z,cnt;
    int fa[M],sum[M],son[M][2];
    int pmax[M],v[M],Root[M],ys[M];
    struct seg_ment{
        int L,R,ls,rs,gl,fla;
    }a[20*M];
    void insert(int &x,const int L,const int R,const int val)
    {
        x=++cnt;a[x].L=L;a[x].R=R;a[x].gl=1;a[x].fla=1;
        if(L==R)return;
        const int mid=L+R>>1;
        if(val<=mid)insert(a[x].ls,L,mid,val);
        else insert(a[x].rs,mid+1,R,val);
    }
    int maxa,maxb;
    void down(const int x)
    {
        if(a[x].fla>1)
        {
            a[x].gl=(ll)a[x].gl*a[x].fla%p;
            a[a[x].ls].fla=(ll)a[a[x].ls].fla*a[x].fla%p;
            a[a[x].rs].fla=(ll)a[a[x].rs].fla*a[x].fla%p;
            a[x].fla=1;
        }
    }
    int merge(int x,int y,int pmax)//合并操作 
    {
        if(!x&&!y)return 0;
        down(x);down(y);
        if(!x)
        {
            maxb=(maxb+a[y].gl)%p;//更新maxb的值 
            a[y].fla*=(maxa+pmax-2ll*maxa*pmax%p+p)%p;
            down(y);
            return y;
        }
        if(!y)
        {
            maxa=(maxa+a[x].gl)%p;//更新maxa的值 
            a[x].fla*=(maxb+pmax-2ll*maxb*pmax%p+p)%p;        
            down(x);    
            return x;
        }
        int d1=a[a[x].rs].gl,d2=a[a[y].rs].gl;
        a[x].rs=merge(a[x].rs,a[y].rs,pmax);
        a[x].ls=merge(a[x].ls,a[y].ls,pmax);
        a[x].gl=(a[a[x].ls].gl+a[a[x].rs].gl)%p;
        return x;
    }
    
    void dfs(const int x)//以dfs顺序完成线段树合并 
    {        
        if(!sum[x])return;
        if(sum[x]==1)dfs(son[x][0]),Root[x]=Root[son[x][0]];
        if(sum[x]==2)
        {
            dfs(son[x][0]);
            dfs(son[x][1]);
            maxa=maxb=0;
            Root[x]=merge(Root[son[x][0]],Root[son[x][1]],pmax[x]);
        }    
    }
    ll ans=0;
    void getans(const int x,const int L,const int R)//遍历求答案 
    {
        if(!a[x].gl)return;
        down(x);
        if(L==R)
        {
            cnt++;
            ans=(ans+(ll)cnt*ys[L]%p*a[x].gl%p*a[x].gl%p)%p;
            return;
        }
        const int mid=L+R>>1;
        getans(a[x].ls,L,mid);getans(a[x].rs,mid+1,R);
    }
    struct node{
        int x,id;
        bool operator <(const node s)const{
            return x<s.x;
        }
    }Q[300010];int top;//离散化 
    int main()
    {
        n=read();
        for(rt i=1;i<=n;i++)
        {
            fa[i]=read();
            son[fa[i]][sum[fa[i]]++]=i;
        }
        for(rt i=1;i<=n;i++)
        if(sum[i])pmax[i]=r*796898467%p;//这是10000模998244353下逆元 
        else Q[++top]=(node){read(),i};
        sort(Q+1,Q+top+1);
        
        for(rt i=1;i<=top;i++)
        ys[i]=Q[i].x,insert(Root[Q[i].id],1,top,i);
        dfs(1);cnt=0;
        getans(Root[1],1,top);cout<<ans;
        return 0;
    }
  • 相关阅读:
    Linux命令汇总(二)
    关于pyspark
    关于CDH
    hive通过spark导入hbase
    CentOS7的网络配置
    TTY,Console以及Terminal
    docker的操作
    docker安装与操作
    Wmware Player中Linux挂载U盘
    Mesos和Marathon
  • 原文地址:https://www.cnblogs.com/DreamlessDreams/p/9048044.html
Copyright © 2020-2023  润新知