LOJ2537:[PKUWC2018]Minimax——题解

https://loj.ac/problem/2537

参考了本题在网上能找到的为数不多的题解。

以及我眼睛瞎没看到需要离散化,还有不开longlong见祖宗。

————————————————————————————

思考一下不难发现,我们的操作相当于对两个数集进行合并,并且重新更新每个数被取到的期望。

权值线段树可以帮我们实现这个功能(当然是要动态开点了)。

然后就思考线段树的合并操作了,orz可我不会啊

设我们期望让左儿子的数字u成为其父亲的权值,其父亲选最大值的概率为k,u在右儿子数集中比它小的数被选中的期望设为w。

则概率为pu*((1-w)*(1-k)+w*k)=pu*(1-w-k+2*w*k)。

当然右儿子同理。

当然统计w显然不能暴力统计,我们权值线段树维护当前区间所有数被选中的期望和,从左到右扫所有可能的最大区间,这个区间满足有一个儿子的数集并不包含这个区间内的任意一个数。

这样这个区间的期望和就能被缩成了“一个数的期望”,此时的w也很容易被统计出来(就相当于这个区间以前的所有数的期望和,每次扫完一个区间累加即可O(1)求出),那么这个时候就被转换成了区间修改问题。

#include<cmath>
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=3e5+5;
const int p=998244353;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
int qpow(int k,int n){
    int res=1;
    while(n){
    if(n&1)res=(ll)res*k%p;
    k=(ll)k*k%p;n>>=1;
    }
    return res;
}
struct tree{
    int l,r;
    ll p,lazy;
}tr[N*20];
int fa[N],son[N],ch[N][2],rt[N],pool,n,m,b[N],q[N];
inline void LSH(){
    sort(b+1,b+m+1);
    m=unique(b+1,b+m+1)-b-1;
    for(int i=1;i<=n;i++)
    if(!son[i])
        q[i]=lower_bound(b+1,b+m+1,q[i])-b;
}
void insert(int &x,int l,int r,int k){
    tr[x=++pool].p=1;tr[x].lazy=1;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(k<=mid)insert(tr[x].l,l,mid,k);
    else insert(tr[x].r,mid+1,r,k);
}
inline void push(int x){
    if(tr[x].lazy<=1)return;
    (tr[tr[x].l].lazy*=tr[x].lazy)%=p;
    (tr[tr[x].r].lazy*=tr[x].lazy)%=p;
    (tr[tr[x].l].p*=tr[x].lazy)%=p;
    (tr[tr[x].r].p*=tr[x].lazy)%=p;
    tr[x].lazy=1;
}
int maxl,maxr;
int merge(int nl,int nr,int l,int r,int k){
    if(!nl&&!nr)return 0;
    if(!nl){
    (maxr+=tr[nr].p)%=p;
    (tr[nr].p*=((ll)2*maxl%p*k%p-k-maxl+1)%p+p)%=p;
    (tr[nr].lazy*=((ll)2*maxl%p*k%p-k-maxl+1)%p+p)%=p;
    return nr;
    }
    if(!nr){
    (maxl+=tr[nl].p)%=p;
    (tr[nl].p*=((ll)2*maxr%p*k%p-k-maxr+1)%p+p)%=p;
    (tr[nl].lazy*=((ll)2*maxr%p*k%p-k-maxr+1)%p+p)%=p;
    return nl;
    }
    push(nl);push(nr);
    int mid=(l+r)>>1;
    tr[nl].l=merge(tr[nl].l,tr[nr].l,l,mid,k);
    tr[nl].r=merge(tr[nl].r,tr[nr].r,mid+1,r,k);
    tr[nl].p=(tr[tr[nl].l].p+tr[tr[nl].r].p)%p;
    return nl;
}
void dfs(int u){
    if(!son[u]){
    insert(rt[u],1,m,q[u]);return;
    }
    if(son[u]==1){
    dfs(ch[u][0]);
    rt[u]=rt[ch[u][0]];
    }else{
    dfs(ch[u][0]);dfs(ch[u][1]);
    maxl=maxr=0;
    rt[u]=merge(rt[ch[u][0]],rt[ch[u][1]],1,m,q[u]);
    }
}
int cnt;
int query(int x,int l,int r){
    if(!tr[x].p)return 0;
    if(l==r){
    cnt++;
    return (ll)cnt*b[l]%p*tr[x].p%p*tr[x].p%p;
    }
    push(x);
    int mid=(l+r)>>1;
    return (query(tr[x].l,l,mid)+query(tr[x].r,mid+1,r))%p;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++){
    fa[i]=read();
    ch[fa[i]][son[fa[i]]++]=i;
    }
    int inv=qpow(10000,p-2);
    for(int i=1;i<=n;i++){
    q[i]=read();
    if(son[i])q[i]=(ll)q[i]*inv%p;
    else b[++m]=q[i];
    }
    LSH();
    dfs(1);
    printf("%d\n",query(rt[1],1,m));
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-06-01 14:30  luyouqi233  阅读(414)  评论(0编辑  收藏  举报