Problem

loj2537

Solution

pkuwc2018最水的一题,要死要活调了一个多小时(1h59min)

我写这题不是因为它有多好,而是为了保持pkuwc2018的队形,与这题类似的有一个好玩得多的题

由于答案的形式和期望相去甚远,所以可以肯定这题和期望无关,而且这么复杂的式子我们最好还是把所有可能计算出来啦

可以肯定地说这题是从叶子向根合并,合并时分类讨论下取最大\((p)\)还是最小\((1-p)\),然后维护前后缀概率和即可

再瞟一眼数据,发现线段树合并可以解决,完结

Code

注意由于线段树合并时若一个节点为空则直接返回,但这棵子树需要乘上整体概率,所以还要在裸的线段树合并中加上标记维护

#include <bits/stdc++.h>
using namespace std;
typedef long long ll; inline void read(int&x){
char c11=getchar();x=0;while(!isdigit(c11))c11=getchar();
while(isdigit(c11))x=x*10+c11-'0',c11=getchar();
} const int N=301050,M=N*10,p=998244353;
struct Edge{int v,nxt;}a[N];
int ls[M],rs[M],f[M],lz[M];
int head[N],c[N],b[N],rt[N];
int n,_,tot; template <typename _tp> inline _tp qm(_tp x){return x<0?x+p:x<p?x:x-p;} void update(int l,int r,int&x,int vl){
if(!x)lz[x=++tot]=1;
if(l==r){f[x]=1;return ;}
int mid(l+r>>1);
if(vl<=mid)update(l,mid,ls[x],vl);
else update(mid+1,r,rs[x],vl);
f[x]=qm(f[ls[x]]+f[rs[x]]);
} inline void mul(int x,int vl){
f[x]=1ll*f[x]*vl%p;
lz[x]=1ll*lz[x]*vl%p;
} inline void down(int x){
if(ls[x])mul(ls[x],lz[x]);
if(rs[x])mul(rs[x],lz[x]);
lz[x]=1;
} int merge(int x,int y,ll p0,ll p1,ll p2){
if(x&&lz[x]!=1)down(x);
if(y&&lz[y]!=1)down(y);
if(!x){mul(y,p0*p1%p+qm(1-p0)*qm(1-p1)%p);return y;}
if(!y){mul(x,p0*p2%p+qm(1-p0)*qm(1-p2)%p);return x;}
rs[x]=merge(rs[x],rs[y],p0,qm(p1+f[ls[x]]),qm(p2+f[ls[y]]));
ls[x]=merge(ls[x],ls[y],p0,p1,p2);
f[x]=qm(f[ls[x]]+f[rs[x]]);
return x;
} void dfs(int x){
for(int i=head[x];i;i=a[i].nxt){
dfs(a[i].v);
if(!rt[x])rt[x]=rt[a[i].v];
else rt[x]=merge(rt[x],rt[a[i].v],c[x],0ll,0ll);
}
if(!head[x])update(1,n,rt[x],c[x]);
} int calc(int l,int r,int x){
if(lz[x]!=1)down(x);
if(l==r)return 1ll*l *b[l]%p *f[x]%p *f[x]%p;
int mid(l+r>>1);
return qm(calc(l,mid,ls[x])+calc(mid+1,r,rs[x]));
} int main(){
read(n);
for(int i=1,x;i<=n;++i){
read(x),a[++_].v=i;
a[_].nxt=head[x],head[x]=_;
}
int tt=0;const ll inv5=796898467;
for(int i=1;i<=n;++i){
read(c[i]);
if(head[i])c[i]=inv5*c[i]%p;
else b[++tt]=c[i];
}
sort(b+1,b+tt+1);
int end=unique(b+1,b+tt+1)-b;
for(int i=1;i<=n;++i)
if(!head[i])c[i]=lower_bound(b+1,b+end,c[i])-b;
n=end-1;dfs(1);
printf("%d\n",calc(1,n,1));
return 0;
}

最新文章

  1. Linux内核笔记——内存管理之slab分配器
  2. Map工具系列-05-添加业务参数工具
  3. MySQL错误:The user specified as a definer (XXX@XXX) does not exist
  4. IOS高级编程之三:IOS 多线程编程
  5. LoadRunner监控Linux
  6. PAT (Basic Level) Practise:1031. 查验身份证
  7. paip.数据挖掘--导出词库 清理太长的iptcode
  8. [ Database ] [ Sybase ] [ SQLServer ] sybase 與SQL Server的界接方式
  9. PHP实现动态生成饼状图、柱状图和折线图(转载)
  10. document.body.clientHeight的取值
  11. 浏览器控制台调试json数据
  12. Spring+EhCache缓存实例(详细讲解+源码下载)
  13. 网站开发进阶(二十九)HTML特殊转义字符
  14. 如何在Visual Studio 2017中使用C# 7+语法
  15. CSS position(定位)属性
  16. Vue基础知识
  17. 【Spark篇】---SparkSQL中自定义UDF和UDAF,开窗函数的应用
  18. python 全栈开发,Day88(csrf_exempt,ES6 快速入门,Vue)
  19. MVC后台获取数据和插入数据的三种方式【二】
  20. 三种初步简易的方法求解数值问题 of C++

热门文章

  1. pom大全
  2. 转 G1垃圾收集器入门
  3. Maccms8.x 命令执行漏洞分析
  4. Elasticsearch 集群 单服务器 超级详细教程
  5. 【leetcode-88,21】 合并两个有序数组/链表
  6. vue.js 树菜单 递归组件树来实现
  7. listView item分割线不显示
  8. SpringBoot入门笔记(二)、使用fastjson
  9. gson和fastjson将json对象转换成javaBean 简单对照
  10. CSS面试复习(一):HTML强化