传送门

思路

首先有一个\(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. 时间格式_java

    @Test public void testDate(){ Date date=new Date(); System.out.println(date); /*日期格式*/ DateFormat df ...

  2. 使用UTF8字符集存储中文生僻字

    使用UTF8字符集存储中文生僻字 一.相关学习BLOG https://www.cnblogs.com/jyzhao/p/8654412.html http://blog.itpub.net/7818 ...

  3. poj 1837 天平问题(01背包变种)

    题意:给你n个挂钩,m个砝码,要求砝码都用上,问有多少中方案数 题解:对于这道题目的状态,我们定义一个变量j为平衡度,当j=0的时候,表明天平平衡.定义dp[i][j]表达的含义为使用前n个砝码的时候 ...

  4. (十四)角色管理(Ztree插件的基本使用)

    1. 建表 角色表 菜单表 角色-菜单(这个表中的role_id和menuu_id都不能被设置为主键,否则当插入一个新角色的时候,一个角色可能拥有多个菜单(role_id重复),一个菜单可能被多个角色 ...

  5. 在论坛中出现的比较难的sql问题:9(触发器专题 插入数据自动更新表数据)

    原文:在论坛中出现的比较难的sql问题:9(触发器专题 插入数据自动更新表数据) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所 ...

  6. Navicat远程连接centos上mysql出错

    原因1:mysql账户是不允许远程连接 参考:centos安装mysql(for 小白) 打开远程连接 原因2:3306端口未开启 开启端口:iptables -I INPUT -p tcp --dp ...

  7. Docker启动Mongo报警告WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.

    警告信息 2019-11-27T09:28:16.659+0000 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_h ...

  8. 三、eureka服务端获取服务列表

    所有文章 https://www.cnblogs.com/lay2017/p/11908715.html 正文 eureka服务端维护了一个服务信息的列表,服务端节点之间相互复制服务信息.而作为eur ...

  9. form-create教程:移除默认提交按钮

    本文将介绍form-create如何修改,隐藏默认提交按钮 form-create 是一个可以通过 JSON 生成具有动态渲染.数据收集.验证和提交功能的表单生成器.并且支持生成任何 Vue 组件.结 ...

  10. 8.读写锁ReadWriteLock

    /*ReadWriteLock 读写锁*/ private ReadWriteLock lock = new ReentrantReadWriteLock(); lock.readLock().loc ...