loj2537 「PKUWC2018」Minimax 【概率 + 线段树合并】
题目链接
题解
观察题目的式子似乎没有什么意义,我们考虑计算出每一种权值的概率
先离散化一下权值
显然可以设一个\(dp\),设\(f[i][j]\)表示\(i\)节点权值为\(j\)的概率
如果\(i\)是叶节点显然
如果\(i\)只有一个儿子直接继承即可
如果\(i\)有两个儿子,对于儿子\(x\),设另一个儿子为\(y\)
则有
\]
直接转移是\(O(n^2)\)的,发现每个节点都有\(O(n)\)个位置需要转移
考虑优化,可以考虑线段树合并
对于一个子树中的权值\(x\),我们记另一棵子树比它大的概率为\(maxa\),
则\(x\)的概率要乘上\(maxa(1 - p_i) + (1 - maxa)p_i = maxa + p_i - 2p_imaxa\)
所以我们在线段树合并过程中,优先合并右子树,并更新两棵子树的\(maxa\)与\(maxb\),就可以在合并过程中转移了
复杂度\(O(nlogn)\)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 300005,maxm = 8000005,INF = 1000000000,P = 998244353;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int n,Ls[maxn],Rs[maxn],b[maxn],N,v10000;
int rt[maxn],sum[maxm],ls[maxm],rs[maxm],tag[maxm],cnt;
int p[maxn],maxa,maxb;
inline int qpow(int a,int b){
int re = 1;
for (; b; b >>= 1,a = 1ll * a * a % P)
if (b & 1) re = 1ll * re * a % P;
return re;
}
inline void pd(int u){
if (tag[u] > 1){
sum[ls[u]] = 1ll * sum[ls[u]] * tag[u] % P;
sum[rs[u]] = 1ll * sum[rs[u]] * tag[u] % P;
tag[ls[u]] = 1ll * tag[ls[u]] * tag[u] % P;
tag[rs[u]] = 1ll * tag[rs[u]] * tag[u] % P;
tag[u] = 1;
}
}
void modify(int& u,int l,int r,int pos){
u = ++cnt; sum[u] = tag[u] = 1;
if (l == r) return;
int mid = l + r >> 1;
if (mid >= pos) modify(ls[u],l,mid,pos);
else modify(rs[u],mid + 1,r,pos);
}
int merge(int u,int v,int p){
if (!u && !v) return 0;
if (!u){
maxb = (maxb + sum[v]) % P;
int tmp;
tmp = (((maxa + p) % P - 2ll * p * maxa % P) % P + P) % P;
sum[v] = 1ll * sum[v] * tmp % P;
tag[v] = 1ll * tag[v] * tmp % P;
return v;
}
if (!v){
maxa = (maxa + sum[u]) % P;
int tmp;
tmp = (((maxb + p) % P - 2ll * p * maxb % P) % P + P) % P;
sum[u] = 1ll * sum[u] * tmp % P;
tag[u] = 1ll * tag[u] * tmp % P;
return u;
}
pd(u); pd(v);
int t = ++cnt; tag[t] = 1;
rs[t] = merge(rs[u],rs[v],p);
ls[t] = merge(ls[u],ls[v],p);
sum[t] = (sum[ls[t]] + sum[rs[t]]) % P;
return t;
}
void dfs(int u){
if (!Ls[u]) modify(rt[u],1,N,p[u]);
else if (!Rs[u]) dfs(Ls[u]),rt[u] = rt[Ls[u]];
else {
dfs(Ls[u]); dfs(Rs[u]);
maxa = maxb = 0;
rt[u] = merge(rt[Ls[u]],rt[Rs[u]],p[u]);
}
}
int ans;
void cal(int u,int l,int r){
if (l == r) {ans = (ans + 1ll * l * b[l] % P * sum[u] % P * sum[u] % P) % P;return;}
pd(u);
int mid = l + r >> 1;
cal(ls[u],l,mid);
cal(rs[u],mid + 1,r);
}
int main(){
n = read(); read(); int x; v10000 = qpow(10000,P - 2);
for (int i = 2; i <= n; i++){
x = read();
if (!Ls[x]) Ls[x] = i;
else Rs[x] = i;
}
for (int i = 1; i <= n; i++){
p[i] = read();
if (!Ls[i]) b[++N] = p[i];
else p[i] = 1ll * p[i] * v10000 % P;
}
sort(b + 1,b + 1 + N);
for (int i = 1; i <= n; i++)
if (!Ls[i]) p[i] = lower_bound(b + 1,b + 1 + N,p[i]) - b;
dfs(1);
cal(rt[1],1,N);
printf("%d\n",ans);
return 0;
}
loj2537 「PKUWC2018」Minimax 【概率 + 线段树合并】的更多相关文章
- LOJ2537. 「PKUWC2018」Minimax【概率DP+线段树合并】
LINK 思路 首先暴力\(n^2\)是很好想的,就是把当前节点概率按照权值大小做前缀和和后缀和然后对于每一个值直接在另一个子树里面算出贡献和就可以了,注意乘上选最大的概率是小于当前权值的部分,选最小 ...
- LOJ2537. 「PKUWC2018」Minimax [DP,线段树合并]
传送门 思路 首先有一个\(O(n^2)\)的简单DP:设\(dp_{x,w}\)为\(x\)的权值为\(w\)的概率. 假设\(w\)来自\(v1\)的子树,那么有 \[ dp_{x,w}=dp_{ ...
- 「洛谷4197」「BZOJ3545」peak【线段树合并】
题目链接 [洛谷] [BZOJ]没有权限号嘤嘤嘤.题号:3545 题解 窝不会克鲁斯卡尔重构树怎么办??? 可以离线乱搞. 我们将所有的操作全都存下来. 为了解决小于等于\(x\)的操作,那么我们按照 ...
- loj#2537. 「PKUWC2018」Minimax
题目链接 loj#2537. 「PKUWC2018」Minimax 题解 设\(f_{u,i}\)表示选取i的概率,l为u的左子节点,r为u的子节点 $f_{u,i} = f_{l,i}(p \sum ...
- 「CQOI2006」简单题 线段树
「CQOI2006」简单题 线段树 水.区间修改,单点查询.用线段树维护区间\([L,R]\)内的所有\(1\)的个数,懒标记表示为当前区间是否需要反转(相对于区间当前状态),下方标记时懒标记取反即可 ...
- 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)$ ...
- [PKUWC2018]Minimax [dp,线段树合并]
好妙的一个题- 我们设 \(f_{i,j}\) 为 \(i\) 节点出现 \(j\) 的概率 设 \(l = ch[i][0] , r = ch[i][1]\) 即左儿子右儿子 设 \(m\) 为叶子 ...
随机推荐
- 微信小程序自定义 tabbar
一定的需求情况下,无法使用小程序原生的 tabbar 的时候,需要自行实现一个和 tabbar 功能一模一样的自制组件. 查阅了海量的博客和文档之后,亲自踩坑.总结了三种在不使用微信小程序原生 tab ...
- GlusterFS分布式存储集群-1. 部署
参考文档: Quick Start Guide:http://gluster.readthedocs.io/en/latest/Quick-Start-Guide/Quickstart/ Instal ...
- 分布式消息队列RocketMQ与Kafka架构上的巨大差异
分布式消息服务 Kafka 是一个高吞吐.高可用的消息中间件服务,适用于构建实时数据管道.流式数据处理.第三方解耦.流量削峰去谷等场景,具有大规模.高可靠.高并发访问.可扩展且完全托管的特点,是分布式 ...
- 2019第十届蓝桥杯C++B组题解(赛后重写的,不确保答案正确性,仅供参考)
先说一下这次的感受吧,我们考场比较乱,开始比赛了,还有的电脑有故障,(向这些人发出同情),第一次认真参加比赛,真正比赛的时候感觉没有那么正式,很乱,各种小问题,(例如博主就没找到题目在哪里,找到后又不 ...
- Tree - AdaBoost with sklearn source code
In the previous post we addressed some issue of decision tree, including instability, lack of smooth ...
- css修改input自动提示的黄色背景
css修改input自动提示的黄色背景 input:-webkit-autofill { background-color: #FAFFBD; background-image: none; -web ...
- 团队作业 & alpha最终测试报告
本次ALPHA版本测试是依据Daily Scrum11.16(http://www.cnblogs.com/newbe/p/4101339.html)分配的任务有序进行的,从11.16~11.23.为 ...
- JAVA开发环境的熟悉
北京电子科技学院(BESTI) 实 验 报 告 课程:Java程序设计 班级:1352 姓名:马悦 学号:20135235 成绩: 指导教师:娄嘉鹏 实验日期:2015.4.13 实验密级: 预习程度 ...
- php与nginx之间的通信
Nginx是俄国人最早开发的Webserver,现在已经风靡全球,相信大家并不陌生.PHP也通过二十多年的发展来到了7系列版本,更加关注性能.这对搭档在最近这些年,叱咤风云,基本上LNMP成了当下的标 ...
- 【大数据应用技术】作业八|爬虫综合大作业Molly134
本次作业的要求来自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3075 前言:本次作业是爬取CBO中国票房2010-2019年每年 ...