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

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

由于此时数的值域变成\([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. FCC---CSS Flexbox: Use the flex-direction Property to Make a Row

    Adding display: flex to an element turns it into a flex container. This makes it possible to align a ...

  2. TimeSpan的用法

    TimeSpan的属性和方法: 下面的列表涵盖了其中的一部分: 属性: Add:与另一个TimeSpan值相加. Days: 返回用天数计算的TimeSpan值.Hours: 返回用小时计算的Time ...

  3. HTML+CSS基础知识点简要汇总(思维导图)

  4. leaflet-webpack 入门开发系列五地图卷帘(附源码下载)

    前言 leaflet-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 w ...

  5. latex 添加Bibtex 全解(使用TeXstudio)

    前提知识: 生成pdf的一般流程 在使用Latex之前,我们一般会借用已有的论文模板,在模板基础上加入我们自己的文章内容,随后编译成PDF文件,其基本流程就是:Latex->Bibtex-> ...

  6. C lang:character input and output (I/O)

    Xx_Introduction Character input and output is by more line character conpose of the text flow  Defin ...

  7. rocksdb学习笔记

    rocksdb是在leveldb的基础上优化而得,解决了leveldb的一些问题. 主要的优化点 1.增加了column family,这样有利于多个不相关的数据集存储在同一个db中,因为不同colu ...

  8. win10,7 80端口被占用的检测和解决方法

    这是一篇关于检测windows7和windows10系统“80端口”被哪个程序占用和怎么解决的小教程.此处用windows10作为范例 1.得到占用该端口的PID ①打开运行(快捷键win+R)(也可 ...

  9. bayaim_Centos7.6_mysql源码5.7-multi_20190424.txt

    用户名/密码mysql/mysql 一.安装mysql: 位置位于 /data/mysql 如果遇到依赖,无法删除,使用 rpm -e --nodeps <包的名字> 不检查依赖,直接删除 ...

  10. 《Web Development with Go》Middleware之使用codegangsta.negroni

    这个第三方库,使用自定义中间件时, 语法就感觉流畅很多. package main import ( "fmt" "log" "net/http&qu ...