Description

给定一棵 \(n\) 个节点的树,每个节点最多有两个子节点。

如果 \(x\) 是叶子,则给定 \(x\) 的权值;否则,它的权值有 \(p_x\) 的概率是它子节点中权值的较大值,\(1-p_x\) 的概率是它子节点中权值的较小值。保证叶子结点权值互不相同。

求根节点所有可能的权值的概率。模 \(998244353\)。

Solution

嗯比较自然的一道题。

设 \(f_{i,x}\) 为结点 \(i\) 权值为 \(x\) 的概率,\(l,r\) 分别是点 \(i\) 的左右子树,则有(假设权值 \(x\) 在 \(l\) 中出现):

\[f_{i,x}=\sum_{j=1}^{x-1}f_{l,x}\cdot f_{r,j}\cdot p_i+\sum_{j=x+1}^n f_{i,x}\cdot f_{r,j}\cdot (1-p_i)
\]

发现这上是一个合并的过程,可以拿线段树合并做。

中间维护两棵树的前缀和后缀和,以及打好标记即可。

Code

LOJ格式化代码真好玩

我能玩一天

放上被LOJ格式化之后的代码

  1. #include <bits/stdc++.h>
  2. using std::max;
  3. using std::min;
  4. using std::swap;
  5. using std::vector;
  6. typedef double db;
  7. typedef long long ll;
  8. #define pb(A) push_back(A)
  9. #define pii std::pair<int, int>
  10. #define all(A) A.begin(), A.end()
  11. #define mp(A, B) std::make_pair(A, B)
  12. #define int long long
  13. const int N = 3e5 + 5;
  14. const int M = N * 20;
  15. const int mod = 998244353;
  16. int sum[M], flag[M], inv;
  17. int val[N], g[N], is[N], ans;
  18. int n, cnt, leaf, head[N], lef;
  19. int ch[M][2], tot, len, rt[N];
  20. struct Edge {
  21. int to, nxt;
  22. } edge[N << 1];
  23. #define ls ch[x][0]
  24. #define rs ch[x][1]
  25. void pushup(int x) { sum[x] = (sum[ls] + sum[rs]) % mod; }
  26. void pushdown(int x) {
  27. if (flag[x] != 1) {
  28. (flag[ls] *= flag[x]) %= mod;
  29. (flag[rs] *= flag[x]) %= mod;
  30. (sum[ls] *= flag[x]) %= mod;
  31. (sum[rs] *= flag[x]) %= mod;
  32. flag[x] = 1;
  33. }
  34. }
  35. void modify(int &x, int l, int r, int ql) {
  36. x = ++tot;
  37. flag[x] = 1;
  38. if (l == r)
  39. return sum[x] = 1, void();
  40. int mid = l + r >> 1;
  41. ql <= mid ? modify(ls, l, mid, ql) : modify(rs, mid + 1, r, ql);
  42. pushup(x);
  43. }
  44. #undef ls
  45. #undef rs
  46. int merge(int x, int y, int aqzh, int ahzh, int bqzh, int bhzh, int pi) {
  47. if (!x and !y)
  48. return 0;
  49. if (!x) {
  50. pushdown(y);
  51. (sum[y] *= ahzh * (1 - pi + mod) % mod + aqzh * pi % mod) %= mod;
  52. (flag[y] *= ahzh * (1 - pi + mod) % mod + aqzh * pi % mod) %= mod;
  53. return y;
  54. }
  55. if (!y) {
  56. pushdown(x);
  57. (sum[x] *= bhzh * (1 - pi + mod) % mod + bqzh * pi % mod) %= mod;
  58. (flag[x] *= bhzh * (1 - pi + mod) % mod + bqzh * pi % mod) %= mod;
  59. return x;
  60. }
  61. int now = ++tot;
  62. flag[now] = 1;
  63. pushdown(x), pushdown(y);
  64. int a = sum[ch[x][0]], b = sum[ch[y][0]];
  65. ch[now][0] =
  66. merge(ch[x][0], ch[y][0], aqzh, (ahzh + sum[ch[x][1]]) % mod, bqzh, (bhzh + sum[ch[y][1]]) % mod, pi);
  67. ch[now][1] = merge(ch[x][1], ch[y][1], (aqzh + a) % mod, ahzh, (bqzh + b) % mod, bhzh, pi);
  68. pushup(now);
  69. return now;
  70. }
  71. void add(int x, int y) {
  72. edge[++cnt].to = y;
  73. edge[cnt].nxt = head[x];
  74. head[x] = cnt;
  75. }
  76. int ksm(int a, int b, int ans = 1) {
  77. while (b) {
  78. if (b & 1)
  79. ans = ans * a % mod;
  80. a = a * a % mod;
  81. b >>= 1;
  82. }
  83. return ans;
  84. }
  85. int getint() {
  86. int X = 0, w = 0;
  87. char ch = getchar();
  88. while (!isdigit(ch)) w |= ch == '-', ch = getchar();
  89. while (isdigit(ch)) X = X * 10 + ch - 48, ch = getchar();
  90. if (w)
  91. return -X;
  92. return X;
  93. }
  94. void dfs(int now) {
  95. if (!is[now])
  96. return;
  97. int tot = 0;
  98. for (int i = head[now]; i; i = edge[i].nxt) {
  99. int to = edge[i].to;
  100. tot++;
  101. dfs(to);
  102. }
  103. if (tot == 1) {
  104. for (int i = head[now]; i; i = edge[i].nxt) {
  105. int to = edge[i].to;
  106. rt[now] = rt[to];
  107. }
  108. } else {
  109. tot = 0;
  110. int a, b;
  111. for (int i = head[now]; i; i = edge[i].nxt) {
  112. int to = edge[i].to;
  113. tot == 1 ? b = to : a = to, tot++;
  114. }
  115. rt[now] = merge(rt[a], rt[b], 0, 0, 0, 0, val[now] * inv % mod);
  116. }
  117. }
  118. void dfs2(int now, int l, int r) {
  119. if (!now)
  120. return;
  121. pushdown(now);
  122. if (l == r)
  123. return (ans += (lef + 1) * g[l] % mod * sum[now] % mod * sum[now] % mod) %= mod, lef++, void();
  124. int mid = l + r >> 1;
  125. dfs2(ch[now][0], l, mid);
  126. dfs2(ch[now][1], mid + 1, r);
  127. }
  128. signed main() {
  129. n = getint();
  130. getint();
  131. inv = ksm(10000, mod - 2);
  132. for (int i = 2; i <= n; i++) {
  133. int x = getint();
  134. add(x, i);
  135. is[x] = 1;
  136. }
  137. for (int i = 1; i <= n; i++) {
  138. val[i] = getint();
  139. if (!is[i])
  140. g[++len] = val[i];
  141. }
  142. std::sort(g + 1, g + 1 + len);
  143. len = std::unique(g + 1, g + 1 + len) - g - 1;
  144. for (int i = 1; i <= n; i++) {
  145. if (!is[i]) {
  146. val[i] = std::lower_bound(g + 1, g + 1 + len, val[i]) - g;
  147. modify(rt[i], 1, len, val[i]);
  148. }
  149. }
  150. dfs(1);
  151. dfs2(rt[1], 1, len);
  152. printf("%lld\n", ans);
  153. return 0;
  154. }

[PKUWC2018] Minimax的更多相关文章

  1. BZOJ5461: [PKUWC2018]Minimax

    BZOJ5461: [PKUWC2018]Minimax https://lydsy.com/JudgeOnline/problem.php?id=5461 分析: 写出\(dp\)式子:$ f[x] ...

  2. 题解-PKUWC2018 Minimax

    Problem loj2537 Solution pkuwc2018最水的一题,要死要活调了一个多小时(1h59min) 我写这题不是因为它有多好,而是为了保持pkuwc2018的队形,与这题类似的有 ...

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

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

  4. LOJ2537 PKUWC2018 Minimax 树形DP、线段树合并

    传送门 题意:自己去看 首先可以知道,每一个点都有几率被选到,所以$i$与$V_i$的关系是确定了的. 所以我们只需要考虑每一个值的取到的概率. 很容易设计出一个$DP$:设$f_{i,j}$为在第$ ...

  5. LOJ2537:[PKUWC2018]Minimax——题解

    https://loj.ac/problem/2537 参考了本题在网上能找到的为数不多的题解. 以及我眼睛瞎没看到需要离散化,还有不开longlong见祖宗. ——————————————————— ...

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

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

  7. 【洛谷5298】[PKUWC2018] Minimax(树形DP+线段树合并)

    点此看题面 大致题意: 有一棵树,给出每个叶节点的点权(互不相同),非叶节点\(x\)至多有两个子节点,且其点权有\(p_x\)的概率是子节点点权较大值,有\(1-p_x\)的概率是子节点点权较小值. ...

  8. Luogu P5298 [PKUWC2018]Minimax

    好劲的题目啊,根本没往线段树合并方面去想啊 首先每种权值都有可能出现,因此我们先排个序然后一个一个求概率 由于此时数的值域变成\([1,m]\)(离散以后),我们可以设一个DP:\(f_{x,i}\) ...

  9. [LOJ2537] [PKUWC2018] Minimax

    题目链接 LOJ:https://loj.ac/problem/2537 洛谷:https://www.luogu.org/problemnew/show/P5298 Solution 不定期诈尸 好 ...

随机推荐

  1. tp5自定义分页参数

    代码示例: $data = db('activity') -> where($condition1)-> order('startline desc') -> paginate(2, ...

  2. 学以致用三十三-----django生命周期

    听了讲解django的视频后,受益匪浅,每个知识点老师都会总结整理.学会总结,存为己用. django生命周期弄明白后,对于整个django的框架会有一个清晰的了解.先上图 1.客户端发送请求,在dj ...

  3. index.php入口文件至根目录

      登录|注册       咖啡如同生活的专栏 从不羡慕别人的优秀,因为相信自己也可以优秀. 闲下来时看看书,书本里的故事,总有你学到的人生.       目录视图 摘要视图 订阅 异步赠书:9月重磅 ...

  4. asp.net项目配置Web.config,支持JSON

    VS2013新建的web项目不支持直接下载json文件,可以在项目的web.config下插入如下的配置信息. <configuration> <system.web> < ...

  5. Layui++>>ajax传递数组,防止深度序列化

  6. roadhog如何支持除development和production外的其他环境变量配置

    roadhog的build和start脚本分别对应了env/development和production,但实践中存在第三种开发环境(可能是预发或集成测试),配置和前两种也都不一样,但现在似乎没办法支 ...

  7. jquery向Django后台发送数组

    在$.ajax中加入 traditional:true, //加上此项可以传数组 后端用 array = request.POST.getlist('ids') #django接收数组 来接收数组

  8. Android开发者的Anko使用指南(三)之资源

    添加依赖 dependencies { compile "org.jetbrains.anko:anko-commons:$anko_version" } Color 0xff00 ...

  9. CCNA学前基础一

    网络设备: 集线器:集线器就是一种采用共享式工作状态的设备.Hub将信号放大后传输给其他端口,即传输线路是共享的. 交换机:用于连接终端设备,和基本的安全功能还有广播域的隔离.优点实现多用户同时访问, ...

  10. CCS3怎么实现border边框渐变效果

    下图注册按钮的边框有渐变效果,如果让你来实现,你会怎么做呢 个人觉得,省事的做法,直接让UI给背景图片就可以了,如下图 不过这种做法感觉不太灵活,如果要修改border的渐变颜色,就需要UI重新做图. ...