传送门

思路

首先有一个\(O(n^2)\)的简单DP:设\(dp_{x,w}\)为\(x\)的权值为\(w\)的概率。

假设\(w\)来自\(v1\)的子树,那么有

\[dp_{x,w}=dp_{v1,w}\times (p\times \sum_{w'>w}dp_{v2,w'}+(1-p)\sum_{w'<w}dp_{v2,w'})
\]

其中\(p\)表示\(x\)选较小权值的概率。

由于每个点的状态数只有子树中的叶子个数,可以考虑线段树合并来优化这一DP过程。

merge(k1,k2,l,r)函数中传进去几个参数:\(v1\)和\(v2\)分别在\([1,l-1]\)的权值和&在\([r+1,n]\)的权值和。当某一个节点为0时就整个子树打乘法tag。

代码

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 303300
#define mod 998244353ll
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char __sr[1<<21],__z[20];int __C=-1,__zz=0;
inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
inline void print(register int x)
{
if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
while(__z[++__zz]=x%10+48,x/=10);
while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
}
void file()
{
#ifdef NTFOrz
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
inline ll MOD(ll x){return x-((mod-x)>>31&mod);} int n;
int w[sz],_w[sz];
struct hh{int t,nxt;}edge[sz<<1];
int head[sz],ecnt;
void make_edge(int f,int t){edge[++ecnt]=(hh){t,head[f]};head[f]=ecnt;}
int son[sz]; int root[sz],cc;
#define Tree sz*30
int ls[Tree],rs[Tree];
ll val[Tree],sum[Tree],tag[Tree];
#define lson ls[k],l,mid
#define rson rs[k],mid+1,r
void Mul(int k,ll w){tag[k]=tag[k]*w%mod;sum[k]=sum[k]*w%mod;val[k]=val[k]*w%mod;}
void pushup(int k){sum[k]=MOD(sum[ls[k]]+sum[rs[k]]);}
void pushdown(int k)
{
if (tag[k]==1) return;
ls[k]&&(Mul(ls[k],tag[k]),0);
rs[k]&&(Mul(rs[k],tag[k]),0);
tag[k]=1;
}
int merge(int k1,int k2,int l,int r,ll pre1,ll suf1,ll pre2,ll suf2,ll p)
{
if (k1+k2==0) return 0;
if (!k1||!k2)
{
if (!k1) swap(k1,k2),swap(pre1,pre2),swap(suf1,suf2);
Mul(k1,MOD(p*suf2%mod+(mod+1-p)*pre2%mod));
return k1;
}
pushdown(k1);pushdown(k2);
int mid=(l+r)>>1,k=++cc;tag[k]=1;
ll L1=sum[ls[k1]],R1=sum[rs[k1]],L2=sum[ls[k2]],R2=sum[rs[k2]];
ls[k]=merge(ls[k1],ls[k2],l,mid,pre1,MOD(suf1+R1),pre2,MOD(suf2+R2),p);
rs[k]=merge(rs[k1],rs[k2],mid+1,r,MOD(pre1+L1),suf1,MOD(pre2+L2),suf2,p);
pushup(k);
return k;
}
void insert(int &k,int l,int r,int x)
{
k=++cc;tag[k]=1;
if (l==r) return (void)(sum[k]=val[k]=1);
int mid=(l+r)>>1;
if (x<=mid) insert(ls[k],l,mid,x);
else insert(rs[k],mid+1,r,x);
pushup(k);
}
ll ans;
void getans(int k,int l,int r)
{
if (!k) return;
if (l==r) return (void)((ans+=1ll*l*_w[l]%mod*val[k]%mod*val[k]%mod)%=mod);
int mid=(l+r)>>1;
pushdown(k);
getans(ls[k],l,mid);getans(rs[k],mid+1,r);
} void dfs(int x)
{
if (!son[x]) return insert(root[x],1,n,w[x]);
int v1=0,v2=0;
go(x) dfs(edge[i].t),(v1?v2:v1)=edge[i].t;
if (!v2) root[x]=root[v1];
else root[x]=merge(root[v1],root[v2],1,n,0,0,0,0,w[x]);
} int main()
{
file();
read(n);
int x;read(x);
rep(i,2,n) read(x),make_edge(x,i),son[x]++;
x=0;
rep(i,1,n) { read(w[i]); if (!son[i]) _w[++x]=w[i]; }
sort(_w+1,_w+x+1);x=unique(_w+1,_w+x+1)-_w-1;
rep(i,1,n)
if (!son[i]) w[i]=lower_bound(_w+1,_w+x+1,w[i])-_w;
else w[i]=(10000-w[i])*inv(10000)%mod;
dfs(1);
getans(root[1],1,n);
cout<<ans;
return 0;
}

LOJ2537. 「PKUWC2018」Minimax [DP,线段树合并]的更多相关文章

  1. LOJ2537. 「PKUWC2018」Minimax【概率DP+线段树合并】

    LINK 思路 首先暴力\(n^2\)是很好想的,就是把当前节点概率按照权值大小做前缀和和后缀和然后对于每一个值直接在另一个子树里面算出贡献和就可以了,注意乘上选最大的概率是小于当前权值的部分,选最小 ...

  2. loj2537 「PKUWC2018」Minimax 【概率 + 线段树合并】

    题目链接 loj2537 题解 观察题目的式子似乎没有什么意义,我们考虑计算出每一种权值的概率 先离散化一下权值 显然可以设一个\(dp\),设\(f[i][j]\)表示\(i\)节点权值为\(j\) ...

  3. BZOJ.5461.[PKUWC2018]Minimax(DP 线段树合并)

    BZOJ LOJ 令\(f[i][j]\)表示以\(i\)为根的子树,权值\(j\)作为根节点的概率. 设\(i\)的两棵子树分别为\(x,y\),记\(p_a\)表示\(f[x][a]\),\(p_ ...

  4. [PKUWC2018]Minimax [dp,线段树合并]

    好妙的一个题- 我们设 \(f_{i,j}\) 为 \(i\) 节点出现 \(j\) 的概率 设 \(l = ch[i][0] , r = ch[i][1]\) 即左儿子右儿子 设 \(m\) 为叶子 ...

  5. 「洛谷4197」「BZOJ3545」peak【线段树合并】

    题目链接 [洛谷] [BZOJ]没有权限号嘤嘤嘤.题号:3545 题解 窝不会克鲁斯卡尔重构树怎么办??? 可以离线乱搞. 我们将所有的操作全都存下来. 为了解决小于等于\(x\)的操作,那么我们按照 ...

  6. loj#2537. 「PKUWC2018」Minimax

    题目链接 loj#2537. 「PKUWC2018」Minimax 题解 设\(f_{u,i}\)表示选取i的概率,l为u的左子节点,r为u的子节点 $f_{u,i} = f_{l,i}(p \sum ...

  7. 「CQOI2006」简单题 线段树

    「CQOI2006」简单题 线段树 水.区间修改,单点查询.用线段树维护区间\([L,R]\)内的所有\(1\)的个数,懒标记表示为当前区间是否需要反转(相对于区间当前状态),下方标记时懒标记取反即可 ...

  8. 【pkuwc2018】 【loj2537】 Minmax DP+线段树合并

    今年年初的时候参加了PKUWC,结果当时这一题想了快$2h$都没有想出来.... 哇我太菜啦.... 昨天突然去搜了下哪里有题,发现$loj$上有于是就去做了下. 结果第一题我5分钟就把所有细节都想好 ...

  9. [BZOJ5461][LOJ#2537[PKUWC2018]Minimax(概率DP+线段树合并)

    还是没有弄清楚线段树合并的时间复杂度是怎么保证的,就当是$O(m\log n)$吧. 这题有一个显然的DP,dp[i][j]表示节点i的值为j的概率,转移时维护前缀后缀和,将4项加起来就好了. 这个感 ...

随机推荐

  1. prometheus+grafana监控redis

    prometheus+grafana监控redis redis安装配置 https://www.cnblogs.com/autohome7390/p/6433956.html redis_export ...

  2. MySQL 解决source 命令导入数据库 乱码

    在我把库.表.sql脚本的编码格式都设置为UTF-8后,任然有乱码,任然有报错: 于是按以下方式重新登录后,解决: mysql -u root -p --default-character-set=u ...

  3. df执行hang住

    一.现象 在linux操作系统中,执行df -h命令,后hang住 二.思路 排查是否存在Nfs问题,无法正常挂载nfs路径导致的问题. 三.解决过程 3.1 cat /etc/rc.local #m ...

  4. Python实现定时执行任务的三种方式简单示例

    本文实例讲述了Python实现定时执行任务的三种方式.分享给大家供大家参考,具体如下: 1.定时任务代码 import time,os,sched schedule = sched.scheduler ...

  5. epoll、mysql概念及简单操作

    epoll 程序阻塞的过程 假设我们目前运行了三个进程A B C ,如果他们都在处于运行态,那就会被加到一个运行队列中 进程A正在运行socket程序 在linux中有句话,万物皆文件,socket对 ...

  6. vue 钩子函数的初接触

    vue-router的路由钩子函数: 第一种:全局钩子函数. router.beforeEach((to, from, next) => { console.log('beforeEach') ...

  7. CentOS linux7 设置开机启动服务

    常用命令 描述                                 旧命令  新命令 使服务自动启动          chkconfig --level 3 http on  syste ...

  8. nc 命令

    目录 nc 命令 一.简介 二.案例 1.端口扫描 2.聊天 3.文件传输 4.目录传输 5.加密网络发送的数据 6.流视频 7.克隆一个设备 8.打开一个shell 9.反向shell 10.指定端 ...

  9. Flutter——AspectRatio组件

    AspectRatio 的作用是根据设置调整子元素 child 的宽高比. AspectRatio 首先会在布局限制条件允许的范围内尽可能的扩展,widget 的高度是由宽度和比率决定的,类似于 Bo ...

  10. import的本质

    import本质? 1定义: 模块:用来从逻辑上组织python代码(变量,函数,类,逻辑:实现一个功能,本质上是一个.py结尾的python文件)(文件:text.py 对应的模块名:text) 包 ...