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

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

由于此时数的值域变成\([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. vue解惑之v-on(事件监听指令)

    一.v-on指令 vue中用v-on指令来监听DOM事件,并触发相应的代码.比如v-on:click,表示监听了点击事件. 二.事件修饰符 在事件处理函数中调用 event.preventDefaul ...

  2. CSRF漏洞原理浅谈

    CSRF漏洞原理浅谈 By : Mirror王宇阳 E-mail : mirrorwangyuyang@gmail.com 笔者并未深挖过CSRF,内容居多是参考<Web安全深度剖析>.& ...

  3. Python语法速查: 7. 函数基础

    返回目录 (1)函数基本 ● 函数是第一类对象 Python中万物皆对象,所有对象都是第一类的(first class),函数也不例外,也是第一类对象.既然是对象,那就可以当作普通的对象数据处理,比如 ...

  4. 《HTTPS权威指南》读书笔记——PKI

    互联网公钥基础设施 基于可信的第三方机构(CA,certification authority)实现不同成员在不见面的情况下进行安全通信 订阅人 需要证书来提供安全服务的团体 登记机构(RA) 完成证 ...

  5. canvas绘制线条详解

    canvas详解----绘制线条 <!DOCTYPE html> <html> <head> <title>canvas详解</title> ...

  6. Python-类的几种调用方法

    一:实例 二:静态 可以调用类以外的变量,只限于此模块. 三:类方法 可以调用该类中定义的变量进行使用. 直接上代码

  7. Web开发跨域问题

    什么是域?    协议,  ip(域名). 端口 前端:域  后端:域   js 进行跨域请求, 因为浏览器的同源策略,导致了两个不同域请求出错 浏览器 会尝试向后端发送 option 请求, --- ...

  8. github用户注册和仓库创建

    访问github官网:https://github.com/,点击注册进入注册页面 输入用户名,电子邮箱和密码后点击下一步 邮箱验证,收到github的验证邮箱,打开后点击验证 选择个人计划 创建仓库 ...

  9. python distutils 基本打包与发布

    distutils 实现对package 包的发布 import math def showMsg(a): return a * a * a a = 10 print('%d 的三次方是 %d' % ...

  10. 在vue组件中设置定时器和清除定时器

    由于项目中难免会碰到需要实时刷新,无论是获取短信码,还是在支付完成后轮询获取当前最新支付状态,这时就需要用到定时器.但是,定时器如果不及时合理地清除,会造成业务逻辑混乱甚至应用卡死的情况,这个时就需要 ...