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}\) ...
随机推荐
- java 获取json字符串中key对应的值
用到了Gson的JsonParser maven项目引入 <dependency> <groupId>com.google.code.gson</groupId> ...
- poj 1837 天平问题(01背包变种)
题意:给你n个挂钩,m个砝码,要求砝码都用上,问有多少中方案数 题解:对于这道题目的状态,我们定义一个变量j为平衡度,当j=0的时候,表明天平平衡.定义dp[i][j]表达的含义为使用前n个砝码的时候 ...
- MySql外网不能访问设置
mysql的root账户,我在连接时通常用的是localhost或127.0.0.1,公司的测试服务器上的mysql也是localhost所以我想访问无法访问,测试暂停. 解决方法如下: 1,修改表, ...
- jQuery_jQuery的两把利器
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- js写guess网页
(一)布局 猜前 -> 猜后 (二)明确实现功能和具体实现: 1.网页生 ...
- 四、TreeSet
HashSet 是无序的,如果要对集合实现排序,那么就需要使用TreeSet 让TreeSet 实现集合有序有两种方法 一.让元素自身具备比较排序功能,具备比较排序功能的元素只需要实现Comparab ...
- Java 之 Map 接口
一.Map 接口概述 java.util.Map 接口专门用来存放键值对这种对象关系的对象. 下面比较一下 Collection 与 Map 的区别: Collection 中的集合,元素是孤立存在的 ...
- 批量删除checkbox前台后台
<%@ page contentType="text/html;charset=UTF-8" %><%@ include file="/WEB-INF/ ...
- ionic 局部刷新
$scope.$on('$ionicView.beforeEnter', console.log("刷新"); })
- 【问题】XShell连接不上Debian root用户
类似文章:https://www.lianst.com/3231.html 修改此文件 重启ssh服务 ssh restart有问题,换一条命令OK 你的Linux发行版可能不一样,针对CentOS参 ...