1 条题解
-
0
自动搬运
来自洛谷,原作者为

OldDriverTree
人間になりたい搬运于
2025-08-24 22:57:00,当前版本为作者最后更新于2024-06-02 22:47:10,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
套路题,学过这题的套路随便推一下就能切出来。
四倍经验
虽然不同,但是套路相同,学过套路能秒出来。
做完这四道题能对这个套路有更好的理解。
- P10332 [UESTCPC 2024] 一站到底
- AT_agc023_f [AGC023F] 01 on Tree
- UVA1205 Color a Tree
- P4437 [HNOI/AHOI2018] 排列
Solution
先考虑假如知道了两个连通块 和 内部的答题顺序,先答哪个连通块最优。
令 为答完 的概率, 为答连通块 的期望得分, 和 同理。
先答 再答 的期望得分为 。
先答 再答 的期望得分为 。
先答 更优当且仅当 ,经过移项得 。
考虑用堆维护每个连通块,一开始每个点为一个连通块,堆顶为 最大的。
每次把堆顶取出来,并把堆顶所在的连通块和堆顶的父亲所在的连通块合并起来,合并后的 和 不难维护,最后的答案就为合并到只剩一个连通块时这个连通块的 ,时间复杂度为 。
Code
//when you use vector or deque,pay attention to the size of it. //by OldDirverTree #include<bits/stdc++.h> #define P pair<double,int> #define int long long #define mid (l+r>>1) using namespace std; const int N=1e5+1; int n,a[N],Fa[N],fa[N]; priority_queue<P> q; double p[N],ans[N]; bool st[N]; int read() { int x=0; bool f=true; char c=0; while (!isdigit(c) ) f&=(c!='-'),c=getchar(); while (isdigit(c) ) x=(x<<3)+(x<<1)+(c&15),c=getchar(); return f?x:-x; } int find(int x) { return fa[x]^x?fa[x]=find(fa[x]):x; } main() { n=read(); for (int i=1;i<=n;i++) a[i]=read(),fa[i]=i; for (int i=1;i<=n;i++) scanf("%lf",&p[i]),ans[i]=p[i]*a[i]; for (int i=2;i<=n;i++) Fa[i]=read(),q.push({(p[i]-1)/ans[i],i}); while (!q.empty() ) { int u=q.top().second; q.pop(); if (st[u]) continue; st[u]=true; int x=find(Fa[u]); fa[u]=x,ans[x]+=p[x]*ans[u],p[x]*=p[u]; if (x^1) q.push({(p[x]-1)/ans[x],x}); } printf("%.9lf",ans[1]); return 0; }
- 1
信息
- ID
- 9973
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者