Luogu P5298 [PKUWC2018]Minimax
好劲的题目啊,根本没往线段树合并方面去想啊
首先每种权值都有可能出现,因此我们先排个序然后一个一个求概率
由于此时数的值域变成\([1,m]\)(离散以后),我们可以设一个DP:\(f_{x,i}\)表示节点\(x\)的权值为\(i\)的概率
转移的话分\(x\)有几个子节点讨论,若没有或是只有一个都是随便转移的
考虑如果有两个,记为\(lc\)和\(rc\),显然我们可以列出转移方程(此时\(i\)在左儿子中,右儿子同理):
\]
我们发现这个式子有一些特征:它转移要乘上的是一段前缀和与一段后缀和,这个如果我们用线段树来维护会很好处理
然后由于每个数只会在一棵子树里,换句话说每个数在每个节点的概率只会造成一次的贡献
更妙的是,我们发现一个数造成贡献的时候由于这一段值域区间乘上的数都是一样的,因此打一个标记每次下传即可
用线段树合并实现,总复杂度\(O(n\log n)\)
#include<cstdio>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=300005,mod=998244353;
struct edge
{
int to,nxt;
}e[N]; int n,head[N],a[N],rst[N],cnt,num,x,rt[N],ans;
inline int sum(CI x,CI y)
{
int t=x+y; return t>=mod?t-mod:t;
}
inline int sub(CI x,CI y)
{
int t=x-y; return t<0?t+mod:t;
}
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void addedge(CI x,CI y)
{
e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
}
class Segment_Tree
{
private:
struct segment
{
int ch[2],val,tag;
}node[N*40]; int tot;
#define lc(x) node[x].ch[0]
#define rc(x) node[x].ch[1]
#define V(x) node[x].val
#define T(x) node[x].tag
#define TN CI l=1,CI r=num
inline void pushdown(CI now)
{
if (T(now)!=1) V(lc(now))=1LL*V(lc(now))*T(now)%mod,V(rc(now))=1LL*V(rc(now))*T(now)%mod,
T(lc(now))=1LL*T(lc(now))*T(now)%mod,T(rc(now))=1LL*T(rc(now))*T(now)%mod,T(now)=1;
}
public:
inline void insert(int& now,CI p,TN)
{
now=++tot; V(now)=T(now)=1; if (l==r) return; int mid=l+r>>1;
if (p<=mid) insert(lc(now),p,l,mid); else insert(rc(now),p,mid+1,r);
}
inline int merge(CI x,CI y,CI p,CI lx=0,CI rx=0,CI ly=0,CI ry=0,TN)
{
if (!x&&!y) return 0; int now=++tot;
if (!y) return pushdown(x),T(now)=sum(1LL*p*ly%mod,1LL*sub(1,p)*ry%mod),
V(now)=1LL*V(x)*T(now)%mod,lc(now)=lc(x),rc(now)=rc(x),now;
if (!x) return pushdown(y),T(now)=sum(1LL*p*lx%mod,1LL*sub(1,p)*rx%mod),
V(now)=1LL*V(y)*T(now)%mod,lc(now)=lc(y),rc(now)=rc(y),now;
int mid=l+r>>1; pushdown(x); pushdown(y); T(now)=1;
lc(now)=merge(lc(x),lc(y),p,lx,sum(rx,V(rc(x))),ly,sum(ry,V(rc(y))),l,mid);
rc(now)=merge(rc(x),rc(y),p,sum(lx,V(lc(x))),rx,sum(ly,V(lc(y))),ry,mid+1,r);
return V(now)=sum(V(lc(now)),V(rc(now))),now;
}
inline int query(CI now,CI p,TN)
{
if (l==r) return V(now); pushdown(now); int mid=l+r>>1;
if (p<=mid) return query(lc(now),p,l,mid); else return query(rc(now),p,mid+1,r);
}
#undef lc
#undef rc
#undef V
#undef T
#undef TN
}SEG;
#define to e[i].to
inline void DFS(CI now=1)
{
if (!head[now]) return SEG.insert(rt[now],lower_bound(rst+1,rst+num+1,a[now])-rst);
for (RI i=head[now];i;i=e[i].nxt) DFS(to),rt[now]=rt[now]?SEG.merge(rt[now],rt[to],a[now]):rt[to];
}
#undef to
int main()
{
RI i; for (scanf("%d",&n),i=1;i<=n;++i) if (scanf("%d",&x),x) addedge(x,i);
for (i=1;i<=n;++i) if (scanf("%d",&a[i]),head[i])
a[i]=1LL*a[i]*quick_pow(10000)%mod; else rst[++num]=a[i];
for (sort(rst+1,rst+num+1),DFS(),i=1;i<=num;++i)
x=SEG.query(rt[1],i),ans=sum(ans,1LL*i*rst[i]%mod*x%mod*x%mod);
return printf("%d",ans),0;
}
Luogu P5298 [PKUWC2018]Minimax的更多相关文章
- BZOJ5461: [PKUWC2018]Minimax
BZOJ5461: [PKUWC2018]Minimax https://lydsy.com/JudgeOnline/problem.php?id=5461 分析: 写出\(dp\)式子:$ f[x] ...
- [LOJ2537] [PKUWC2018] Minimax
题目链接 LOJ:https://loj.ac/problem/2537 洛谷:https://www.luogu.org/problemnew/show/P5298 Solution 不定期诈尸 好 ...
- 题解-PKUWC2018 Minimax
Problem loj2537 Solution pkuwc2018最水的一题,要死要活调了一个多小时(1h59min) 我写这题不是因为它有多好,而是为了保持pkuwc2018的队形,与这题类似的有 ...
- [PKUWC2018] Minimax
Description 给定一棵 \(n\) 个节点的树,每个节点最多有两个子节点. 如果 \(x\) 是叶子,则给定 \(x\) 的权值:否则,它的权值有 \(p_x\) 的概率是它子节点中权值的较 ...
- BZOJ.5461.[PKUWC2018]Minimax(DP 线段树合并)
BZOJ LOJ 令\(f[i][j]\)表示以\(i\)为根的子树,权值\(j\)作为根节点的概率. 设\(i\)的两棵子树分别为\(x,y\),记\(p_a\)表示\(f[x][a]\),\(p_ ...
- LOJ2537 PKUWC2018 Minimax 树形DP、线段树合并
传送门 题意:自己去看 首先可以知道,每一个点都有几率被选到,所以$i$与$V_i$的关系是确定了的. 所以我们只需要考虑每一个值的取到的概率. 很容易设计出一个$DP$:设$f_{i,j}$为在第$ ...
- LOJ2537:[PKUWC2018]Minimax——题解
https://loj.ac/problem/2537 参考了本题在网上能找到的为数不多的题解. 以及我眼睛瞎没看到需要离散化,还有不开longlong见祖宗. ——————————————————— ...
- [BZOJ5461][LOJ#2537[PKUWC2018]Minimax(概率DP+线段树合并)
还是没有弄清楚线段树合并的时间复杂度是怎么保证的,就当是$O(m\log n)$吧. 这题有一个显然的DP,dp[i][j]表示节点i的值为j的概率,转移时维护前缀后缀和,将4项加起来就好了. 这个感 ...
- 【洛谷5298】[PKUWC2018] Minimax(树形DP+线段树合并)
点此看题面 大致题意: 有一棵树,给出每个叶节点的点权(互不相同),非叶节点\(x\)至多有两个子节点,且其点权有\(p_x\)的概率是子节点点权较大值,有\(1-p_x\)的概率是子节点点权较小值. ...
随机推荐
- JavaScript 递归遍历json串获取相关数据
递归遍历json串获取相关数据 by:授客 QQ:1033553122 1. 测试数据 // 导航菜单 [ { id: 1, parentId: 0, parentName: null, na ...
- EXCEPTION_ACCESS_VIOLATION(0xc0000005)
EXCEPTION_ACCESS_VIOLATION(0xc0000005)eclipse.ini中添加:-XX:CompileCommand=exclude,org.eclipse.jdt.inte ...
- 坚果云+typora(个人十分喜欢的一个记笔记方式)
1.名称 坚果云 markdown--->typora 2.喜欢原因 2.1 坚果云 坚果云全平台覆盖,支持Windows.Mac.Linux.iOS(iPad及iPhone).Android. ...
- IDEA编译报错Error:java: Compilation failed: internal java compiler error
根据报错可以知道是编译某个模块报错, 接下来就是检查这个模块的编译版本 解决办法很简单:File-->Setting...-->Build,Execution,Deployment--&g ...
- js 运算的内置函数
// 一.Math.round()作用:四舍五入返回整数.(返回参数+0.5后,向下取整) // Math.round(5.57) //返回6 // Math.round(2.4) //返回2 // ...
- 《2019年小米春季上海 PHP 实习生招聘面试题》部分答案解析
1 丶 Nginx 怎么实现负载均衡 这个还是比较简单 1.轮询 这种是默认的策略,把每个请求按顺序逐一分配到不同的 server,如果 server 挂掉,能自动剔除. 2.最少连接 把请求分配到连 ...
- 微软、IBM、GitLab 等大厂全部到齐的 OCS 第一天有什么看点?
在本周一的推文中我们大致介绍了下 Open Core 峰会及到场嘉宾,(≧▽≦) 当然还有 Nebula Graph 在会场的展位位置图,本文我们来看看 Open Core 峰会第一天有哪些值得一看的 ...
- Spring Boot AOP解析
Spring Boot AOP 面向切面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP). OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面. AOP(Aspec ...
- Kubernetes的Job对象
Deployment.StatefulSet及DaemonSet三个主要用来进行长时间业务,不会退出. 而有一些离线业务,或者叫Batch Job(计算业务),计算完成后就直接退出 了,如果用Depl ...
- 一起学SpringMVC之Json
本文主要以一个简单的小例子,简述SpringMVC开发中,Json的相关应用,仅供学习分享使用,如有不足之处,还请指正. 什么是Json ? JSON 指的是 JavaScript 对象表示法(Jav ...