\(\mathscr{Description}\)

  Link.

  给定一棵二叉树,每片叶子有一个权值,所有权值互不相同。每个非叶结点 \(u\) 有一个概率 \(p_u\in(0,1)\),表示 \(u\) 的权值以 \(p_u\) 的概率取儿子最大权值,以 \(1-p_u\) 的概率取儿子最小权值。求根节点取到每种权值的概率(以一定形式压缩输出)。答案模 \(998244353\)。

\(\mathscr{Solution}\)

  令 \(f(u,i)\) 表示 \(u\) 处取到全局第 \(i\) 大的权值的概率,设 \(u\) 的左右儿子为 \(l,r\),显然

\[f(u,i)=f(l,i)\left(p_u\sum_{j<i}f(r,j)+(1-p_u)\sum_{j>i}f(r,j)\right)+f(r,i)\left(p_u\sum_{j<i}f(l,j)+(1-p_u)\sum_{j>i}f(l,j)\right).
\]

这是个左右区间的交叉贡献,用权值线段树维护 \(f(u)\),我们居然能直接将 \(f(l)\) 和 \(f(r)\) 的树“混合”直接求出 \(f(u)\)!

  注意,例如左对右有贡献,直接在右子树上打乘法或加法之类的标记是不良的——不同时间戳下的标记合并方式不同。因而,我们可以暴力地保证,当且仅当线段树结点 \(u\) 的后代不会被打上当前时间戳的标记(即,\(u\) 子树内的贡献因子都一样了),我们才给它打乘法标记;否则仅累加系数递归传递。

  所有贡献完成后,我们再把 \(f'(l)\) 和 \(f'(r)\) 合并(对应点贡献相加),就得到了 \(f(u)\)。本质上就是做了两次线段树合并,所以复杂度是 \(\mathcal O(n\log n)\)。

  那么这件事情告诉我们线段树无所不能,所有看似暴力的 DP 都拿来试一试。(

\(\mathscr{Code}\)

/*+Rainybunny+*/

#include <bits/stdc++.h>

#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i) const int MAXN = 3e5, MOD = 998244353, INV1E4 = 796898467;
int n, siz[MAXN + 5], ch[MAXN + 5][2], val[MAXN + 5];
int mxv, dc[MAXN + 5], root[MAXN + 5]; inline int mul(const int u, const int v) { return 1ll * u * v % MOD; }
inline void subeq(int& u, const int v) { (u -= v) < 0 && (u += MOD); }
inline int sub(int u, const int v) { return (u -= v) < 0 ? u + MOD : u; }
inline void addeq(int& u, const int v) { (u += v) >= MOD && (u -= MOD); }
inline int add(int u, const int v) { return (u += v) < MOD ? u : u - MOD; } struct SegmentTree {
static const int MAXND = 3e6;
int node, ch[MAXND][2], sum[MAXND], tag[MAXND]; inline void pushup(const int u) {
sum[u] = add(sum[ch[u][0]], sum[ch[u][1]]);
} inline void pushml(const int u, const int v) {
assert(u);
sum[u] = mul(sum[u], v), tag[u] = mul(tag[u], v);
} inline void pushdn(const int u) {
if (tag[u] != 1) {
if (ch[u][0]) pushml(ch[u][0], tag[u]);
if (ch[u][1]) pushml(ch[u][1], tag[u]);
tag[u] = 1;
}
} inline void insert(int& u, const int l, const int r, const int x) {
u = ++node, tag[u] = sum[u] = 1;
if (l == r) return ;
int mid = l + r >> 1;
if (x <= mid) insert(ch[u][0], l, mid, x);
else insert(ch[u][1], mid + 1, r, x);
} inline void mix(const int u, const int v,
const int su, const int sv, const int p) {
if (!u && !v) return ;
if (u && !v) return pushml(u, su);
if (v && !u) return pushml(v, sv);
if (!ch[u][0] && !ch[u][1]) return pushml(u, su), pushml(v, sv);
pushdn(u), pushdn(v);
int ul = sum[ch[u][0]], ur = sum[ch[u][1]];
int vl = sum[ch[v][0]], vr = sum[ch[v][1]], q = sub(1, p);
mix(ch[u][0], ch[v][0], add(su, mul(q, vr)), add(sv, mul(q, ur)), p);
mix(ch[u][1], ch[v][1], add(su, mul(p, vl)), add(sv, mul(p, ul)), p);
pushup(u), pushup(v);
} inline void merge(int& u, const int v) {
if (!u || !v) return void(u |= v);
if (!ch[u][0] && !ch[u][1]) return addeq(sum[u], sum[v]);
pushdn(u), pushdn(v), addeq(sum[u], sum[v]);
merge(ch[u][0], ch[v][0]), merge(ch[u][1], ch[v][1]);
} inline int answer(const int u, const int l, const int r) {
if (l == r) return mul(mul(l, dc[l]), mul(sum[u], sum[u]));
int mid = l + r >> 1, ret = 0; pushdn(u);
addeq(ret, answer(ch[u][0], l, mid));
addeq(ret, answer(ch[u][1], mid + 1, r));
return ret;
}
} sgt; inline void solve(const int u) {
if (!ch[u][0]) {
val[u] = std::lower_bound(dc + 1, dc + mxv + 1, val[u]) - dc;
sgt.insert(root[u], 1, mxv, val[u]);
} else if (!ch[u][1]) {
solve(ch[u][0]), root[u] = root[ch[u][0]];
} else {
solve(ch[u][0]), solve(ch[u][1]);
sgt.mix(root[ch[u][0]], root[ch[u][1]], 0, 0, val[u]);
sgt.merge(root[u] = root[ch[u][0]], root[ch[u][1]]);
}
} int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0); std::cin >> n;
rep (i, 1, n) {
int fa; std::cin >> fa;
if (fa) ch[fa][!!ch[fa][0]] = i;
}
rep (i, 1, n) {
std::cin >> val[i];
if (ch[i][0]) val[i] = mul(val[i], INV1E4);
else dc[++mxv] = val[i];
} std::sort(dc + 1, dc + mxv + 1);
mxv = std::unique(dc + 1, dc + mxv + 1) - dc - 1;
solve(1); std::cout << sgt.answer(root[1], 1, mxv) << '\n';
return 0;
}

Solution -「PKUWC 2018」「洛谷 P5298」Minimax的更多相关文章

  1. LOJ #2542. 「PKUWC 2018」随机游走(最值反演 + 树上期望dp + FMT)

    写在这道题前面 : 网上的一些题解都不讲那个系数是怎么推得真的不良心 TAT (不是每个人都有那么厉害啊 , 我好菜啊) 而且 LOJ 过的代码千篇一律 ... 那个系数根本看不出来是什么啊 TAT ...

  2. LOJ #2541. 「PKUWC 2018」猎人杀(容斥 , 期望dp , NTT优化)

    题意 LOJ #2541. 「PKUWC 2018」猎人杀 题解 一道及其巧妙的题 , 参考了一下这位大佬的博客 ... 令 \(\displaystyle A = \sum_{i=1}^{n} w_ ...

  3. LOJ #2540. 「PKUWC 2018」随机算法(概率dp)

    题意 LOJ #2540. 「PKUWC 2018」随机算法 题解 朴素的就是 \(O(n3^n)\) dp 写了一下有 \(50pts\) ... 大概就是每个点有三个状态 , 考虑了但不在独立集中 ...

  4. LOJ #2538. 「PKUWC 2018」Slay the Spire (期望dp)

    Update on 1.5 学了 zhou888 的写法,真是又短又快. 并且空间是 \(O(n)\) 的,速度十分优秀. 题意 LOJ #2538. 「PKUWC 2018」Slay the Spi ...

  5. 「区间DP」「洛谷P1043」数字游戏

    「洛谷P1043」数字游戏 日后再写 代码 /*#!/bin/sh dir=$GEDIT_CURRENT_DOCUMENT_DIR name=$GEDIT_CURRENT_DOCUMENT_NAME ...

  6. Solution -「JSOI 2019」「洛谷 P5334」节日庆典

    \(\mathscr{Description}\)   Link.   给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的).   \(|S|\le3\time ...

  7. Solution -「洛谷 P4372」Out of Sorts P

    \(\mathcal{Description}\)   OurOJ & 洛谷 P4372(几乎一致)   设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...

  8. Solution -「POI 2010」「洛谷 P3511」MOS-Bridges

    \(\mathcal{Description}\)   Link.(洛谷上这翻译真的一言难尽呐.   给定一个 \(n\) 个点 \(m\) 条边的无向图,一条边 \((u,v,a,b)\) 表示从 ...

  9. Solution -「APIO 2016」「洛谷 P3643」划艇

    \(\mathcal{Description}\)   Link & 双倍经验.   给定 \(n\) 个区间 \([a_i,b_i)\)(注意原题是闭区间,这里只为方便后文描述),求 \(\ ...

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

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

随机推荐

  1. CSS动画(波光粼粼登录页面)

    1.整体效果 https://mmbiz.qpic.cn/sz_mmbiz_gif/EGZdlrTDJa4AbemkU3vLRIDzTIgPHSjicia97wfvMVAhqZL4lsGbQQCbsV ...

  2. Go语言基础05 _string

    Go语言基础05 _string 1.基本使用 package string import "testing" func TestString(t *testing.T) { va ...

  3. 2024 CSP 游记

    \(\text{CSP-J}\) 游记 \(\text{Day -INF}\) 初赛免了,没有游记. \(\text{Day 0}\) 有点慌,于是打开了游戏跟 \(\text{zjx,sym}\) ...

  4. 内核源码+vscode+bear+clang实现函数任意跳转,无缝跳转,无缝阅读,无缝开发

    一.准备工作 1.内核源码版本选择 务必有一份能编译通过的<内核源码>,本次选择5.10版本的. #说明:5.10版本的<内核源码>里,在 scripts/clang-tool ...

  5. 用 300 行代码手写提炼 Spring 核心原理 [3]

    系列文章 用 300 行代码手写提炼 Spring 核心原理 [1] 用 300 行代码手写提炼 Spring 核心原理 [2] 用 300 行代码手写提炼 Spring 核心原理 [3] 上文 中我 ...

  6. 鸿蒙NEXT开发案例:随机密码生成

    [引言] 本案例将实现一个随机密码生成器.用户可以自定义密码的长度以及包含的字符类型(大写字母.小写字母.数字.特殊字符),最后通过点击按钮生成密码,并提供一键复制功能. [环境准备] •操作系统:W ...

  7. lua中table中null的表示方法以及判断redis返回null

    今天遇到一个麻烦的问题,查询redis时候,查到数据的时候正常返回,查询不到数据时,返回了null,然而在lua中,常见的nil,但不常见null,这时候lua中对redis返回的null如何做判断呢 ...

  8. 借助AI助手如何高效排查SQL问题

    快乐的时光总是转瞬即逝,尤其是当我们面对bug时,不仅浪费了宝贵的时间,更让人感到沮丧.因为bug往往是非常奇怪.难以捉摸的,找来找去你始终无法确定问题所在,最终意识到这些bug并没有多大技术含量.尽 ...

  9. 基本ROP

    ret2text [NewStarCTF 2023 公开赛道]ret2text (64) execve本身并不是一个后门函数. 实际上,execve是一个标准的系统调用函数,用于在 Linux和类 U ...

  10. 02C++顺序结构(1)

    1.C++程序的样子 2.流 输出流 COUT<< 3.一个实例及解析 4.小结 头文件的解释 头文件是C++程序对其他程序的引用,就是让编译器的预处理器把这个输入输出流的标准文件iost ...