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

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

由于此时数的值域变成\([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. jsp + js + 前端弹出框

    在项目中,前端页面我们时常需要各种各样的弹出框: 1.alert对话框:显示含有给定消息的"JavaScript Alert"对话框 代码: var a = "Hello ...

  2. Pluralsight 科技公司公布自己的avaScript 成为最受欢迎的开发技术

    根据 SDTimes 报道,Pluralsight 科技公司公布自己的 Technology Index,JavaScript 位居榜首. Pluralsight,是美国的一家面向软件开发者的在线教育 ...

  3. Android 极光IM-高级篇-玩聊天app诞生

    距离上一次写 基础篇有了4个月,终于我写了一个 功能完善的即时通讯app,作为高级篇的担当出现.废话不多说,上图 app预览 ​​​​ ​​​​ ​​ 实现功能 1.用户的登录注册 2.单聊,能清空聊 ...

  4. VS2017创建的单元测试不支持顺序测试

      问题:使用IDE创建的单元测试项目,标准引用是,导致不能添加顺序测试,复制其它项目的顺序测试文件进行编辑时,也会提示基于MSTest V2的测试不能用于顺序测试     解决办法: 移除自带的NU ...

  5. 创建以.xxx开头的文件夹的方法

    在windows下创建以.xxx开头的文件夹时,点击确认,系统提示“必须键入文件名”. 最方便的方法: (1)新建文件夹 (3)在文件名.xxxxx后再加一个.,也就是把文件名改成这样子:.XXXXX ...

  6. Samba共享文件

    1 安装samba yum install -y samba* 2 添加用户 useradd smbuser 3 设置共享文件用户的密码 smbpasswd -a smbuser 4 创建公共共享文件 ...

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

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

  8. [译]Vulkan教程(17)帧缓存

    [译]Vulkan教程(17)帧缓存 Framebuffers 帧缓存 We've talked a lot about framebuffers in the past few chapters a ...

  9. flask的模板引擎jinja入门教程 包含一个通过网络实时传输Video视频流的示例

    本文首发于个人博客https://kezunlin.me/post/1e37a6/,欢迎阅读最新内容! tutorial to use python flask jinja templates and ...

  10. Windows10+texlive2018+texstudio

    texlive2018+texstudio下载链接 链接: https://pan.baidu.com/s/1KjPJnw1kwMBCu3qGT9rIUg 提取码: g8ha 安装texlive 解压 ...