好劲的题目啊,根本没往线段树合并方面去想啊

首先每种权值都有可能出现,因此我们先排个序然后一个一个求概率

由于此时数的值域变成\([1,m]\)(离散以后),我们可以设一个DP:\(f_{x,i}\)表示节点\(x\)的权值为\(i\)的概率

转移的话分\(x\)有几个子节点讨论,若没有或是只有一个都是随便转移的

考虑如果有两个,记为\(lc\)和\(rc\),显然我们可以列出转移方程(此时\(i\)在左儿子中,右儿子同理):

\[f_{x,i}=f_{lc,i}\times(p_x\times \sum_{j=1}^{i-1} f_{rc,j}+(1-p_x)\sum_{j=i+1}^m f_{rc,j})
\]

我们发现这个式子有一些特征:它转移要乘上的是一段前缀和与一段后缀和,这个如果我们用线段树来维护会很好处理

然后由于每个数只会在一棵子树里,换句话说每个数在每个节点的概率只会造成一次的贡献

更妙的是,我们发现一个数造成贡献的时候由于这一段值域区间乘上的数都是一样的,因此打一个标记每次下传即可

用线段树合并实现,总复杂度\(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的更多相关文章

  1. BZOJ5461: [PKUWC2018]Minimax

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

  2. [LOJ2537] [PKUWC2018] Minimax

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

  3. 题解-PKUWC2018 Minimax

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

  4. [PKUWC2018] Minimax

    Description 给定一棵 \(n\) 个节点的树,每个节点最多有两个子节点. 如果 \(x\) 是叶子,则给定 \(x\) 的权值:否则,它的权值有 \(p_x\) 的概率是它子节点中权值的较 ...

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. C#本地文件下载以及FTP文件服务下载(以Pdf文件为例)

    一.C#实现本地文件下载 1.文件下载的路径  文件名称 以及文件下载之后要放的位置  这三个变量是必须要的 2.定义以下四个对象: FileWebRequest ftpWebRequest = nu ...

  2. android sdk tools里找不到draw9patch.bat 如何制作.9.png 格式图片

    1.什么是.9.png格式 .9.png格式的图片可以在安卓平台指定拉伸区域,防止图片失真,一般用作背景图. 2.前提 最近项目中要用到.9.png格式图片,想着这个简单使用draw9patch.ba ...

  3. 属性文件——Java&Spring

    属性文件 什么是属性文件 ? 定义:一个扩展名为properties文件,属性文件都是以key-value(键值对)来保存文件的内容,如:log4j.properties,db.properties等 ...

  4. CALL和RET指令实验

    实验10 1.在屏幕8行3列,用绿色显示data段中的字符串 assume cs:code data segment db data ends code segment start: ;行 ;列 ;颜 ...

  5. Java Swing 图形界面开发

    https://blog.csdn.net/xietansheng/article/details/72814492

  6. Java之Map接口(双列集合)

    Map集合概述 现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射.Java提供了专门的集合类用来存放这种对象关系的对 ...

  7. 第04组 Beta冲刺(3/4)

    队名:斗地组 组长博客:地址 作业博客:Beta冲刺(3/4) 各组员情况 林涛(组长) 过去两天完成了哪些任务: 1.分配展示任务 2.收集各个组员的进度 3.写博客 展示GitHub当日代码/文档 ...

  8. RN调试坑点总结(不定期更新)

    前言 我感觉,如果模拟器是个人的话,我已经想打死他了 大家不要催我学flutter啦,哈哈哈,学了后跟大家分享下 RN报错的终极解决办法 众所周知,RN经常遇到无可奈何的超级Bug, 那么对于这些问题 ...

  9. .net core 在 Docker 上的部署

    Docker可以说是现在微服务,DevOps的基础,咱们.Net Core自然也得上Docker..Net Core发布到Docker容器的教程网上也有不少,但是今天还是想来写一写.你搜.Net co ...

  10. IT兄弟连 HTML5教程 HTML5表单 小结及习题

    小结 HTML表单提交的方法有get方法和post方法,get方法的作用是从指定的资源请求数据,post方法的作用是向指定的资源提交要被处理的数据.HTML表单一直都是Web的核心技术之一,有了它我们 ...