Luogu5298 [PKUWC2018]Minimax
太久没写博客了,过来水一发。
题目链接:洛谷
首先我们想到,考虑每个叶节点的权值为根节点权值的概率。首先要将叶节点权值离散化。
假设现在是$x$节点,令$f_i,g_i$分别表示左/右节点的权值$=i$的概率。
若$w_x$来自于左儿子,则
$$P(w_x=i)=f_i*(p_x*\sum_{j=1}^{i-1}g_j+(1-p)*\sum_{j=i+1}^mg_j)$$
右儿子也是一样的。
所以在转移的时候需要顺便维护$f,g$的前/后缀和。
但是我们发现这样直接跑是$O(n^2)$的,肯定不行,但是每个节点的所有dp值都只依赖于两个儿子,而且区间乘法是可以使用lazy_tag的,所以可以使用线段树合并。
(等会儿,好像之前并没有写过。。。)
线段树合并就是对于值域线段树,合并的时候如果两棵树都有这个节点,那么就递归下去,否则直接按照上面的式子转移。
$f,g$的前/后缀和也可以放在参数里面顺便维护了。
#include<bits/stdc++.h>
#define Rint register int
using namespace std;
typedef long long LL;
const int N = , mod = , inv = ;
int n, v[N], tot, p[N], fa[N], head[N], to[N], nxt[N];
inline void add(int a, int b){
static int cnt = ;
to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt;
}
int root[N], ls[N << ], rs[N << ], seg[N << ], tag[N << ], cnt, ans;
inline void pushdown(int x){
if(x && tag[x] != ){
if(ls[x]){
seg[ls[x]] = (LL) seg[ls[x]] * tag[x] % mod;
tag[ls[x]] = (LL) tag[ls[x]] * tag[x] % mod;
}
if(rs[x]){
seg[rs[x]] = (LL) seg[rs[x]] * tag[x] % mod;
tag[rs[x]] = (LL) tag[rs[x]] * tag[x] % mod;
}
tag[x] = ;
}
}
inline void change(int &x, int L, int R, int pos){
if(!x) tag[x = ++ cnt] = ;
pushdown(x);
++ seg[x];
if(seg[x] >= mod) seg[x] = ;
if(L == R) return;
int mid = L + R >> ;
if(pos <= mid) change(ls[x], L, mid, pos);
else change(rs[x], mid + , R, pos);
}
inline int merge(int lx, int rx, int L, int R, int pl, int pr, int sl, int sr, int P){
if(!lx && !rx) return ;
int now = ++ cnt, mid = L + R >> ; tag[now] = ;
pushdown(lx); pushdown(rx);
if(!lx){
int v = ((LL) P * sl + (mod + 1ll - P) * sr) % mod;
seg[now] = (LL) seg[rx] * v % mod;
tag[now] = (LL) tag[rx] * v % mod;
ls[now] = ls[rx]; rs[now] = rs[rx];
return now;
}
if(!rx){
int v = ((LL) P * pl + (mod + 1ll - P) * pr) % mod;
seg[now] = (LL) seg[lx] * v % mod;
tag[now] = (LL) tag[lx] * v % mod;
ls[now] = ls[lx]; rs[now] = rs[lx];
return now;
}
ls[now] = merge(ls[lx], ls[rx], L, mid, pl, (pr + seg[rs[rx]]) % mod, sl, (sr + seg[rs[lx]]) % mod, P);
rs[now] = merge(rs[lx], rs[rx], mid + , R, (pl + seg[ls[rx]]) % mod, pr, (sl + seg[ls[lx]]) % mod, sr, P);
seg[now] = (seg[ls[now]] + seg[rs[now]]) % mod;
return now;
}
inline void getans(int x, int L, int R){
pushdown(x);
if(L == R){
ans = (ans + (LL) seg[x] * seg[x] % mod * v[L] % mod * L % mod) % mod;
return;
}
int mid = L + R >> ;
getans(ls[x], L, mid);
getans(rs[x], mid + , R);
}
inline void dfs(int x){
if(!head[x]){
change(root[x], , n, p[x]);
return;
}
for(Rint i = head[x];i;i = nxt[i]){
dfs(to[i]);
if(!root[x]) root[x] = root[to[i]];
else root[x] = merge(root[x], root[to[i]], , n, , , , , p[x]);
}
}
int main(){
scanf("%d", &n);
for(Rint i = ;i <= n;i ++){
scanf("%d", fa + i);
if(fa[i]) add(fa[i], i);
}
for(Rint i = ;i <= n;i ++){
scanf("%d", p + i);
if(head[i]) p[i] = (LL) p[i] * inv % mod;
else v[++ tot] = p[i];
}
sort(v + , v + tot + );
for(Rint i = ;i <= n;i ++)
if(!head[i]) p[i] = lower_bound(v + , v + tot + , p[i]) - v;
dfs();
getans(root[], , n);
printf("%d", ans);
}
luogu5369
Luogu5298 [PKUWC2018]Minimax的更多相关文章
- BZOJ5461: [PKUWC2018]Minimax
BZOJ5461: [PKUWC2018]Minimax https://lydsy.com/JudgeOnline/problem.php?id=5461 分析: 写出\(dp\)式子:$ f[x] ...
- 题解-PKUWC2018 Minimax
Problem loj2537 Solution pkuwc2018最水的一题,要死要活调了一个多小时(1h59min) 我写这题不是因为它有多好,而是为了保持pkuwc2018的队形,与这题类似的有 ...
- [PKUWC2018] Minimax
Description 给定一棵 \(n\) 个节点的树,每个节点最多有两个子节点. 如果 \(x\) 是叶子,则给定 \(x\) 的权值:否则,它的权值有 \(p_x\) 的概率是它子节点中权值的较 ...
- BZOJ.5461.[PKUWC2018]Minimax(DP 线段树合并)
BZOJ LOJ 令\(f[i][j]\)表示以\(i\)为根的子树,权值\(j\)作为根节点的概率. 设\(i\)的两棵子树分别为\(x,y\),记\(p_a\)表示\(f[x][a]\),\(p_ ...
- LOJ2537 PKUWC2018 Minimax 树形DP、线段树合并
传送门 题意:自己去看 首先可以知道,每一个点都有几率被选到,所以$i$与$V_i$的关系是确定了的. 所以我们只需要考虑每一个值的取到的概率. 很容易设计出一个$DP$:设$f_{i,j}$为在第$ ...
- LOJ2537:[PKUWC2018]Minimax——题解
https://loj.ac/problem/2537 参考了本题在网上能找到的为数不多的题解. 以及我眼睛瞎没看到需要离散化,还有不开longlong见祖宗. ——————————————————— ...
- [BZOJ5461][LOJ#2537[PKUWC2018]Minimax(概率DP+线段树合并)
还是没有弄清楚线段树合并的时间复杂度是怎么保证的,就当是$O(m\log n)$吧. 这题有一个显然的DP,dp[i][j]表示节点i的值为j的概率,转移时维护前缀后缀和,将4项加起来就好了. 这个感 ...
- 【洛谷5298】[PKUWC2018] Minimax(树形DP+线段树合并)
点此看题面 大致题意: 有一棵树,给出每个叶节点的点权(互不相同),非叶节点\(x\)至多有两个子节点,且其点权有\(p_x\)的概率是子节点点权较大值,有\(1-p_x\)的概率是子节点点权较小值. ...
- Luogu P5298 [PKUWC2018]Minimax
好劲的题目啊,根本没往线段树合并方面去想啊 首先每种权值都有可能出现,因此我们先排个序然后一个一个求概率 由于此时数的值域变成\([1,m]\)(离散以后),我们可以设一个DP:\(f_{x,i}\) ...
随机推荐
- uboot 与 代码重定位
ref: https://blog.csdn.net/dhauwd/article/details/78566668 https://blog.csdn.net/yueqian_scut/articl ...
- 怎样理解script标签的defer属性和async属性
如果script标签是引用的外部js文件, 那就会有一个下载js文件这一过程, 为了不因为这个下载过程而阻塞页面解析与渲染, 我们需要一种机制来解决这一问题, 方法之一就是使用 defer和async ...
- (五)mybatis之一对一关系
一.需求分析 需求:查询订单信息关联查询用户信息 分析:一条订单只能由一个消费者来下单,也就是说从订单的角度来说与消费者是一对一的关系. 二.建数据库表和实体对象 其中订单表中的字段user_id对应 ...
- (三)调用web服务
(二)发布第一个WebService服务与DSWL文档解析讲解了如何发布一个web服务,本章主要讲述如何调用一个web服务. 这里有三种方式: 使用代理模式调用,需要将服务端的接口类拷贝到客户端中.( ...
- 查准率(precision)和查全率(recall)
一.理解查准率(precision)& 查全率(recall) 我们在平时常用到的模型评估指标是精度(accuracy)和错误率(error rate),错误率是:分类错误的样本数站样本总数的 ...
- C#从零单排上王者系列---元组
从零单排系列说明 博主最初的想法是想写个蜕茧成蝶的系列文章,后来觉得博客的表现形式很难做到连贯和系统.所以从本篇博客开始博主会选择书中比较重要和不好理解的知识点并结合自己的实际工作经验来讲解,不再是照 ...
- 微软发布云端基因服务:推动AI驱动的精准医疗
微软发布云端基因服务:推动AI驱动的精准医疗 2018年03月07日 00:00:00 微软研究院AI头条 阅读数:117 版权声明:本文为博主原创文章,未经博主允许不得转载. https:// ...
- kong命令(四)upstream
介绍 upstream 就是一个虚拟的服务.可用于配置多个target目标服务时实现负载均衡的效果. 注意:service的host指的就是upstream的name. 同时upstream提供了一个 ...
- pytorch自定义网络层以及损失函数
转自:https://blog.csdn.net/dss_dssssd/article/details/82977170 https://blog.csdn.net/dss_dssssd/articl ...
- 恺撒密码 B
恺撒密码 B ...