传送门

思路

首先有一个\(O(n^2)\)的简单DP:设\(dp_{x,w}\)为\(x\)的权值为\(w\)的概率。

假设\(w\)来自\(v1\)的子树,那么有

\[dp_{x,w}=dp_{v1,w}\times (p\times \sum_{w'>w}dp_{v2,w'}+(1-p)\sum_{w'<w}dp_{v2,w'})
\]

其中\(p\)表示\(x\)选较小权值的概率。

由于每个点的状态数只有子树中的叶子个数,可以考虑线段树合并来优化这一DP过程。

merge(k1,k2,l,r)函数中传进去几个参数:\(v1\)和\(v2\)分别在\([1,l-1]\)的权值和&在\([r+1,n]\)的权值和。当某一个节点为0时就整个子树打乘法tag。

代码

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 303300
#define mod 998244353ll
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char __sr[1<<21],__z[20];int __C=-1,__zz=0;
inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
inline void print(register int x)
{
if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
while(__z[++__zz]=x%10+48,x/=10);
while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
}
void file()
{
#ifdef NTFOrz
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
inline ll MOD(ll x){return x-((mod-x)>>31&mod);} int n;
int w[sz],_w[sz];
struct hh{int t,nxt;}edge[sz<<1];
int head[sz],ecnt;
void make_edge(int f,int t){edge[++ecnt]=(hh){t,head[f]};head[f]=ecnt;}
int son[sz]; int root[sz],cc;
#define Tree sz*30
int ls[Tree],rs[Tree];
ll val[Tree],sum[Tree],tag[Tree];
#define lson ls[k],l,mid
#define rson rs[k],mid+1,r
void Mul(int k,ll w){tag[k]=tag[k]*w%mod;sum[k]=sum[k]*w%mod;val[k]=val[k]*w%mod;}
void pushup(int k){sum[k]=MOD(sum[ls[k]]+sum[rs[k]]);}
void pushdown(int k)
{
if (tag[k]==1) return;
ls[k]&&(Mul(ls[k],tag[k]),0);
rs[k]&&(Mul(rs[k],tag[k]),0);
tag[k]=1;
}
int merge(int k1,int k2,int l,int r,ll pre1,ll suf1,ll pre2,ll suf2,ll p)
{
if (k1+k2==0) return 0;
if (!k1||!k2)
{
if (!k1) swap(k1,k2),swap(pre1,pre2),swap(suf1,suf2);
Mul(k1,MOD(p*suf2%mod+(mod+1-p)*pre2%mod));
return k1;
}
pushdown(k1);pushdown(k2);
int mid=(l+r)>>1,k=++cc;tag[k]=1;
ll L1=sum[ls[k1]],R1=sum[rs[k1]],L2=sum[ls[k2]],R2=sum[rs[k2]];
ls[k]=merge(ls[k1],ls[k2],l,mid,pre1,MOD(suf1+R1),pre2,MOD(suf2+R2),p);
rs[k]=merge(rs[k1],rs[k2],mid+1,r,MOD(pre1+L1),suf1,MOD(pre2+L2),suf2,p);
pushup(k);
return k;
}
void insert(int &k,int l,int r,int x)
{
k=++cc;tag[k]=1;
if (l==r) return (void)(sum[k]=val[k]=1);
int mid=(l+r)>>1;
if (x<=mid) insert(ls[k],l,mid,x);
else insert(rs[k],mid+1,r,x);
pushup(k);
}
ll ans;
void getans(int k,int l,int r)
{
if (!k) return;
if (l==r) return (void)((ans+=1ll*l*_w[l]%mod*val[k]%mod*val[k]%mod)%=mod);
int mid=(l+r)>>1;
pushdown(k);
getans(ls[k],l,mid);getans(rs[k],mid+1,r);
} void dfs(int x)
{
if (!son[x]) return insert(root[x],1,n,w[x]);
int v1=0,v2=0;
go(x) dfs(edge[i].t),(v1?v2:v1)=edge[i].t;
if (!v2) root[x]=root[v1];
else root[x]=merge(root[v1],root[v2],1,n,0,0,0,0,w[x]);
} int main()
{
file();
read(n);
int x;read(x);
rep(i,2,n) read(x),make_edge(x,i),son[x]++;
x=0;
rep(i,1,n) { read(w[i]); if (!son[i]) _w[++x]=w[i]; }
sort(_w+1,_w+x+1);x=unique(_w+1,_w+x+1)-_w-1;
rep(i,1,n)
if (!son[i]) w[i]=lower_bound(_w+1,_w+x+1,w[i])-_w;
else w[i]=(10000-w[i])*inv(10000)%mod;
dfs(1);
getans(root[1],1,n);
cout<<ans;
return 0;
}

LOJ2537. 「PKUWC2018」Minimax [DP,线段树合并]的更多相关文章

  1. LOJ2537. 「PKUWC2018」Minimax【概率DP+线段树合并】

    LINK 思路 首先暴力\(n^2\)是很好想的,就是把当前节点概率按照权值大小做前缀和和后缀和然后对于每一个值直接在另一个子树里面算出贡献和就可以了,注意乘上选最大的概率是小于当前权值的部分,选最小 ...

  2. loj2537 「PKUWC2018」Minimax 【概率 + 线段树合并】

    题目链接 loj2537 题解 观察题目的式子似乎没有什么意义,我们考虑计算出每一种权值的概率 先离散化一下权值 显然可以设一个\(dp\),设\(f[i][j]\)表示\(i\)节点权值为\(j\) ...

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

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

  4. [PKUWC2018]Minimax [dp,线段树合并]

    好妙的一个题- 我们设 \(f_{i,j}\) 为 \(i\) 节点出现 \(j\) 的概率 设 \(l = ch[i][0] , r = ch[i][1]\) 即左儿子右儿子 设 \(m\) 为叶子 ...

  5. 「洛谷4197」「BZOJ3545」peak【线段树合并】

    题目链接 [洛谷] [BZOJ]没有权限号嘤嘤嘤.题号:3545 题解 窝不会克鲁斯卡尔重构树怎么办??? 可以离线乱搞. 我们将所有的操作全都存下来. 为了解决小于等于\(x\)的操作,那么我们按照 ...

  6. loj#2537. 「PKUWC2018」Minimax

    题目链接 loj#2537. 「PKUWC2018」Minimax 题解 设\(f_{u,i}\)表示选取i的概率,l为u的左子节点,r为u的子节点 $f_{u,i} = f_{l,i}(p \sum ...

  7. 「CQOI2006」简单题 线段树

    「CQOI2006」简单题 线段树 水.区间修改,单点查询.用线段树维护区间\([L,R]\)内的所有\(1\)的个数,懒标记表示为当前区间是否需要反转(相对于区间当前状态),下方标记时懒标记取反即可 ...

  8. 【pkuwc2018】 【loj2537】 Minmax DP+线段树合并

    今年年初的时候参加了PKUWC,结果当时这一题想了快$2h$都没有想出来.... 哇我太菜啦.... 昨天突然去搜了下哪里有题,发现$loj$上有于是就去做了下. 结果第一题我5分钟就把所有细节都想好 ...

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

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

随机推荐

  1. asp.net core-2.在vs2017中创建asp.net core应用程序

    今天我们用vs2017创建一个asp.net core 的应用程序,打开vs2017 点击:文件—>项目,选择asp.net core web 应用程序 点击确定 红框内就昨天用控制台去创建的应 ...

  2. T4模板使用笔记

    路径获取 ① 获取当前解决方案路径 string solutionsPath = Host.ResolveAssemblyReference("$(SolutionDir)"); ...

  3. sys.dm_exec_query_stats的total_worker_time的单位是微秒还是毫秒

    该视图sys.dm_exec_query_stats存放的就是当前所有执行计划的详细信息,比如某条执行计划共占CPU多少等等.因为该视图对编译次数.占用CPU资源总量.执行次数等都进行了详细的记录,所 ...

  4. MQTTnet 3.0.5学习笔记

    段时间在使用MQTTnet,都说这个东西比较好,可是翻了翻网上没有例子给参考一下. 今天算是找到了,给高手的帖子做个宣传吧. 原网址如下:https://blog.csdn.net/chenlu520 ...

  5. Jar包下载 开源网站 模板下载

    在日常的java学习和开发中,总是遇到各种jar包下载,但是CSDN这种坑爹网站,各位码农们都想挣点C币,一个开源的免费的东西就这么变了味,我这里收集 了一些好用的工具,日常开发中需要用的请自取,毕竟 ...

  6. VisualSVN 关于权限(第2篇)

    最终的答案: 仓库本身不能给他增加访问权限,必须增加否则连不上,不增加的时候 他默认就是No Access: 仓库本身可以理解为:祖宗,他是访问权限的根基.子目录会继承他的权限. 那么既然必须给他增加 ...

  7. class类 - static

    不需要实例化类,即可直接通过该类来调用的方法,即称之为"静态方法".将类中的方法设为静态方法也很简单,在方法前加上static关键字即可.这样该方法就不会被实例继承! class ...

  8. 【外网不好用】可以尝试添加dns即可解决上不去外网的问题。

    可以将IPv4这里的DNS修改成以下内容再尝试上网试试.

  9. Oracle中select 1和select *的区别

    转自:https://www.linuxidc.com/Linux/2010-05/26202.htm 创建myt表并插入数据,如下: create table myt(name varchar2,c ...

  10. OpenCV 图象腐蚀形态学操作 全家桶

    图象腐蚀与形态学操作 opencv 1. 通过调用库函数实现图像的腐蚀.膨胀: 2. 通过设置结构元素.元素大小.形态学操作类型实现对图象的形态学操作. 源码(VS2017+OpenCV 4.0) # ...