LOJ2537. 「PKUWC2018」Minimax【概率DP+线段树合并】
思路
首先暴力\(n^2\)是很好想的,就是把当前节点概率按照权值大小做前缀和和后缀和然后对于每一个值直接在另一个子树里面算出贡献和就可以了,注意乘上选最大的概率是小于当前权值的部分,选最小是大于当前权值的部分
然后考虑怎么优化
用线段树合并来做
每次向左递归的时候就把x右子树对y左子树的贡献加上,把y右子树对x左子树的贡献加上
每次向左递归的时候就把x左子树对y右子树的贡献加上,把y左子树对x右子树的贡献加上
考虑每个节点,左边的区间贡献一定会被统计完全,右边的区间贡献一定会被统计完全
然后这样统计下来所有的点都是被更新了的
所以只需要动态开点线段树维护一个区间和和区间乘标记就可以了
然后就做完了
注意dfs的边界,如果只有一个儿子就可以直接赋值了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace io {
const int BUFSIZE = 1 << 20;
char ibuf[BUFSIZE], *is = ibuf, *it = ibuf;
char obuf[BUFSIZE], *os = obuf, *ot = obuf + BUFSIZE - 1;
char read_char() {
if (is == it)
it = (is = ibuf) + fread(ibuf, 1, BUFSIZE, stdin);
return *is++;
}
int read_int() {
int x = 0, f = 1;
char c = read_char();
while (!isdigit(c)) {
if (c == '-') f = -1;
c = read_char();
}
while (isdigit(c)) x = x * 10 + c - '0', c = read_char();
return x * f;
}
ll read_ll() {
ll x = 0, f = 1;
char c = read_char();
while (!isdigit(c)) {
if (c == '-') f = -1;
c = read_char();
}
while (isdigit(c)) x = x * 10 + c - '0', c = read_char();
return x * f;
}
void read_string(char* s) {
char c = read_char();
while (isspace(c)) c = read_char();
while (!isspace(c)) *s++ = c, c = read_char();
*s = 0;
}
void flush() {
fwrite(obuf, 1, os - obuf, stdout);
os = obuf;
}
void print_char(char c) {
*os++ = c;
if (os == ot) flush();
}
void print_int(int x) {
static char q[20];
if (!x) print_char('0');
else {
if (x < 0) print_char('-'), x = -x;
int top = 0;
while (x) q[top++] = x % 10 + '0', x /= 10;
while (top--) print_char(q[top]);
}
}
void print_ll(ll x) {
static char q[20];
if (!x) print_char('0');
else {
if (x < 0) print_char('-'), x = -x;
int top = 0;
while (x) q[top++] = x % 10 + '0', x /= 10;
while (top--) print_char(q[top]);
}
}
struct flusher_t {
~flusher_t() {
flush();
}
} flusher;
};
using namespace io;
const int Mod = 998244353;
const int N = 3e5 + 10;
const int LOG = 50;
int rt[N], ls[N * LOG], rs[N * LOG], val[N * LOG], tag[N * LOG];
int ld[N], rd[N], tot = 0;
int n, m, w[N], pre[N], pos[N];
int add(int a, int b) {
return (a += b) >= Mod ? a - Mod : a;
}
int sub(int a, int b) {
return (a -= b) < 0 ? a + Mod : a;
}
int mul(int a, int b) {
return (long long) a * b % Mod;
}
int fast_pow(int a, int b) {
int res = 1;
for (; b; b >>= 1, a = mul(a, a))
if (b & 1) res = mul(res, a);
return res;
}
void pushup(int t) {
val[t] = add(val[ls[t]], val[rs[t]]);
}
void pushnow(int t, int vl) {
if (!t) return;
val[t] = mul(val[t], vl);
tag[t] = mul(tag[t], vl);
}
void pushdown(int t) {
if (tag[t] != 1) {
pushnow(ls[t], tag[t]);
pushnow(rs[t], tag[t]);
tag[t] = 1;
}
}
void insert(int &t, int l, int r, int pos) {
t = ++tot;
tag[t] = val[t] = 1;
if (l == r) return;
int mid = (l + r) >> 1;
if (pos <= mid) insert(ls[t], l, mid, pos);
else insert(rs[t], mid + 1, r, pos);
}
int merge(int x, int y, int sumx, int sumy, int promin, int promax) {
if (!y) {pushnow(x, sumx); return x;}
if (!x) {pushnow(y, sumy); return y;}
pushdown(x), pushdown(y);
int prex = val[ls[x]], sufx = val[rs[x]];
int prey = val[ls[y]], sufy = val[rs[y]];
// 必须要提前声明 不然会被修改
ls[x] = merge(ls[x], ls[y], add(sumx, mul(promin, sufy)), add(sumy, mul(promin, sufx)), promin, promax);
rs[x] = merge(rs[x], rs[y], add(sumx, mul(promax, prey)), add(sumy, mul(promax, prex)), promin, promax);
pushup(x);
return x;
}
void dfs(int u) {
if (!u) return;
dfs(ld[u]), dfs(rd[u]);
if (!ld[u]) {
insert(rt[u], 1, m, pos[u]);
} else if (!rd[u]) { // 特判
rt[u] = rt[ld[u]];
} else {
rt[u] = merge(rt[ld[u]], rt[rd[u]], 0, 0, sub(1, w[u]), w[u]);
}
}
int calc(int t, int l, int r) {
if (!t) return 0;
if (l == r) return mul(mul(mul(val[t], val[t]), pre[l]), l);
pushdown(t);
int mid = (l + r) >> 1;
return add(calc(ls[t], l, mid), calc(rs[t], mid + 1, r));
}
int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
n = read_int();
int inv = fast_pow(10000, Mod - 2);
for (int i = 1; i <= n; i++) {
int fa = read_int();
if (!ld[fa]) ld[fa] = i;
else rd[fa] = i;
}
for (int i = 1; i <= n; i++) {
w[i] = read_int();
if (ld[i]) w[i] = mul(w[i], inv);
else pre[++m] = w[i];
}
sort(pre + 1, pre + m + 1);
for (int i = 1; i <= n; i++)
if (!ld[i]) pos[i] = lower_bound(pre + 1, pre + m + 1, w[i]) - pre;
dfs(1);
print_int(calc(rt[1], 1, m));
return 0;
}
LOJ2537. 「PKUWC2018」Minimax【概率DP+线段树合并】的更多相关文章
- [BZOJ5461][LOJ#2537[PKUWC2018]Minimax(概率DP+线段树合并)
还是没有弄清楚线段树合并的时间复杂度是怎么保证的,就当是$O(m\log n)$吧. 这题有一个显然的DP,dp[i][j]表示节点i的值为j的概率,转移时维护前缀后缀和,将4项加起来就好了. 这个感 ...
- loj2537 「PKUWC2018」Minimax 【概率 + 线段树合并】
题目链接 loj2537 题解 观察题目的式子似乎没有什么意义,我们考虑计算出每一种权值的概率 先离散化一下权值 显然可以设一个\(dp\),设\(f[i][j]\)表示\(i\)节点权值为\(j\) ...
- LOJ2537. 「PKUWC2018」Minimax [DP,线段树合并]
传送门 思路 首先有一个\(O(n^2)\)的简单DP:设\(dp_{x,w}\)为\(x\)的权值为\(w\)的概率. 假设\(w\)来自\(v1\)的子树,那么有 \[ dp_{x,w}=dp_{ ...
- loj#2537. 「PKUWC2018」Minimax
题目链接 loj#2537. 「PKUWC2018」Minimax 题解 设\(f_{u,i}\)表示选取i的概率,l为u的左子节点,r为u的子节点 $f_{u,i} = f_{l,i}(p \sum ...
- 【LOJ】#3109. 「TJOI2019」甲苯先生的线段树
LOJ#3109. 「TJOI2019」甲苯先生的线段树 发现如果枚举路径两边的长度的话,如果根节点的值是$x$,左边走了$l$,右边走了$r$ 肯定答案会是$(2^{l + 1} + 2^{r + ...
- 【pkuwc2018】 【loj2537】 Minmax DP+线段树合并
今年年初的时候参加了PKUWC,结果当时这一题想了快$2h$都没有想出来.... 哇我太菜啦.... 昨天突然去搜了下哪里有题,发现$loj$上有于是就去做了下. 结果第一题我5分钟就把所有细节都想好 ...
- BZOJ.5461.[PKUWC2018]Minimax(DP 线段树合并)
BZOJ LOJ 令\(f[i][j]\)表示以\(i\)为根的子树,权值\(j\)作为根节点的概率. 设\(i\)的两棵子树分别为\(x,y\),记\(p_a\)表示\(f[x][a]\),\(p_ ...
- 【LOJ】#2537. 「PKUWC2018」Minimax
题解 加法没写取模然后gg了QwQ,de了半天 思想还是比较自然的,线段树合并的维护方法我是真的很少写,然后没想到 很显然,我们有个很愉快的想法是,对于每个节点枚举它所有的叶子节点,对于一个叶子节点的 ...
- 「PKUWC2018」Minimax
题面 题解 强势安利一波巨佬的$blog$ 线段树合并吼题啊 合并的时候要记一下$A$点权值小于$l$的概率和$A$点权值大于$r$的概率,对$B$点同样做 时空复杂度$\text O(nlogw)$ ...
随机推荐
- Python mysql-表的创建,删除和更新
2017-09-06 20:59:56 数据库的创建 CREATE DATEBASE <数据库的名称> 表的创建 CREATE TABLE <表名> (<列名1> ...
- js如何创建JSON对象
js如何创建JSON对象 一.总结 一句话总结:直接创建js数组和js对象即可,然后JSON.stringify就可以获取json字符串,js中的一切都是对象,而且js中的对象都是json对象 js ...
- C#,ArcGIS Engine开发入门教程
C#,ArcGIS Engine开发入门教程 转自:http://blog.csdn.net/yanleigis/article/details/2233674 目录(?)[+] 五实现 一 加载A ...
- POJ-1160 Post Office (DP+四边形不等式优化)
题目大意:有v个村庄成直线排列,要建设p个邮局,为了使每一个村庄到离它最近的邮局的距离之和最小,应该怎样分配邮局的建设,输出最小距离和. 题目分析:定义状态dp(i,j)表示建设 i 个邮局最远覆盖到 ...
- hihoCoder-1087 Hamiltonian Cycle (记忆化搜索)
描述 Given a directed graph containing n vertice (numbered from 1 to n) and m edges. Can you tell us h ...
- Razor视图引擎 语法学习
下面就和大家分享下我在asp.net官网看到的资料,学习到的点语法.1.通过使用@符号,可以直接在html页面中写C#或者VB代码:运行后: 2.页面中的C#或者VB代码都放在大括号中.运行后: 3. ...
- Spring Data Rest如何暴露ID字段
package com.example.demo.config; import com.example.demo.model.Comp; import com.example.demo.model.P ...
- 33. 81. Search in Rotated Sorted Array *HARD*
Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 migh ...
- Sentry项目监控工具结合vue的安装与使用(前端)
一.官网:https://sentry.io/welcome/ 二.介绍 Sentry 是一个开源的实时错误报告工具,支持 web 前后端.移动应用以及游戏,支持 Python.OC.Java.Go. ...
- laravel 连接同一服务器上多个数据库操作 、 连接多个不同服务器上的不同数据库操作以及多个数据库操作的事务处理
!注意:标红的要注意区分开 第一步.配置.env文件(同一服务器上多个数据库) DB_CONNECTION=pgsqlDB_HOST=IP(例如:127.0.0.1)DB_PORT=端口号(例如:54 ...