P15265 [USACO26JAN2] Dynamic Instability P 自学式题解
| 符号 | 含义 |
|---|---|
| \(f\) | \(x\) 的父节点 |
| \(deg_x\) | \(x\) 的儿子个数 |
| \(dep_x\) | \(x\) 的深度 |
| \(A_x\) | \(x\) 的祖先集合(包含自己) |
大期望,因为我不大会这种东西所以自己重新推一边顺便写篇题解,洛谷题解已经说的很明白了所以这篇不发洛谷。
换为等价的操作:
一个非叶子节点往下走,而往上跳的过程拆成一步一步不花时间的,在 \(x\) 点有 \(\frac{1}{dep_x}\) 的概率停下,而那一秒在叶子节点加进去就可以了。这样根据古典概型经典结论跟原问题是等价的。
设从根节点走到 \(x\) 节点期望时间为 \(E_x\),从父节点走到 \(x\) 的期望时间为 \(down_x\),则有 \(E_x=E_{f}+down_x\)(期望线性性质)。
考虑怎么求 \(down_x\):
它有 \(\frac{1}{deg_{f}}\) 的概率从父节点跑下来,这一步要跑 \(1\) 秒。但是也有可能是从父节点跑到兄弟节点子树(这一步也是一秒),再跳回父节点的祖先(这里每个祖先概率均等),再下来回到父节点,然后回到我们一开始的问题,即从父节点到 \(x\) 的期望时间。
再设从 \(x\) 跳进来再第一次跳出 \(x\) 子树的期望时间为 \(out_x\),对 \(down_x\) 写出转移:
解方程则有
再求 \(out_x\):
如果 \(x\) 是叶子,则有 \(out_x=1\) ,因为我们要把往上跳的代价算上。
否则它将等概率地从每个子树跳出来,根据我们转化后的问题,从子树跳到 \(x\) 这一步的代价一定是 \(0\),而它有 \(\frac{1}{dep_x}\) 的概率停住,如果停住则回到了原来的问题;否则有 \(\frac{dep_x-1}{dep_x}\) 概率跳出去,然而这个向上跳的代价是 \(0\):
解方程得出:
那怎么求答案呢?
设 \(\texttt{lca}(x,y)=l\)。如果 \(x=l\),则直接向下跳就好了,\(ans=E_y-E_x\)。
设 \(g_{x,l}\) 为上行跳到 \(x\),再向上跑到 \(l\) 的期望时间。
跳到 \(x\) 时,它有 \(\frac{1}{dep_x}\) 的概率停住然后往下走再跳回来,所以有 \(g_{x,l}=\frac{1}{dep_x}out_x+g_{f,l}\),显然可以合并为 \(g_{x,l}=\sum_{v\in path_{x,l},v\not=l}\frac{out_v}{dep_v}\)。
\(x\) 先跑到 \(l\),它有可能再往上跳,不过那些贡献都是 \(0\),以这些起点向下跑到 \(y\)。
也就是:
为什么不是 \(out_x+\sum_{v\in A_l}(g_{f,v}+E_y-E_v)\)?因为 \(g_{x,v}\) 包含了它中途停下往下跑的情况,而 \(down_v\) 也包含了,这就算重了,只能算到最近公共祖先。
这些东西都按照式子算就做完了。
code
#include <bits/stdc++.h>
#define int int64_t
//#define int __int128
#define MOD (1000000007)
//#define eps (1e-6)
#define endl '\n'
#define debug_endl cout<<endl;
#define debug cout<<"debug"<<endl;
namespace Easy_Count{
template<typename T>
inline int mod_plus(T val) { return val % MOD; }
template<typename T, typename... Rest>
inline int mod_plus(T first, Rest... rest) {
return (static_cast<long long>(first % MOD) + mod_plus(rest...)) % MOD;
}
template<typename T>
inline int mod_mul(T val) { return val % MOD; }
template<typename T, typename... Rest>
inline int mod_mul(T first, Rest... rest) {
return (static_cast<long long>(first % MOD) * mod_mul(rest...)) % MOD;
}
inline int mod(int x){
return (x%MOD+MOD)%MOD;
}
inline int qpow(int a,int b){
int res=1;
while(b){
if(b&1){
res=(res*a)%MOD;
}
a=(a*a)%MOD;
b>>=1;
}
return res;
}
}
using namespace Easy_Count;
using namespace std;
const int MAXN=2e5+10;
int n,q,dep[MAXN],down[MAXN],out[MAXN],inv[MAXN],E[MAXN],fa[MAXN][21],preE[MAXN],t,preg[MAXN];
vector<int> g[MAXN];
void dfs1(int x){
int deg=g[x].size(),sum=0;
if(deg==0){
out[x]=1;
return ;
}
for(int v:g[x]){
dep[v]=dep[x]+1;
dfs1(v);
sum=(sum+out[v])%MOD;
}
if(x!=1) out[x]=mod_mul(dep[x],inv[dep[x]-1],mod_plus(1,mod_mul(inv[deg],sum)));
}
void dfs2(int x,int Es,int f){
fa[x][0]=f;
for(int i=1;i<=t;++i) fa[x][i]=fa[fa[x][i-1]][i-1];
int sum=0,deg=g[x].size();
for(int v:g[x]) sum=mod_plus(sum,out[v]);
E[x]=mod_plus(E[f],down[x]);
int newE=(Es+E[x])%MOD;
preE[x]=newE;
preg[x]=mod_plus(preg[f],mod_mul(inv[dep[x]],out[x]));
for(int v:g[x]){
down[v]=mod_plus(deg,mod_mul(deg-1,inv[dep[x]],mod(dep[x]*E[x]-newE)),mod(sum-out[v]));
dfs2(v,newE,x);
}
}
inline int LCA(int x,int y){
if(dep[x]!=dep[y]){
if(dep[x]<dep[y]) swap(x,y);
int o=dep[x]-dep[y];
for(int i=0;o;++i){
if(o&1) x=fa[x][i];
o>>=1;
}
}
if(x==y) return x;
for(int i=t;i>=0;--i){
if(fa[x][i]!=fa[y][i]){
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
signed main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>q;
t=__lg(n);
inv[1]=1;
for(int i=2;i<=n;++i){
int p;
cin>>p;
g[p].emplace_back(i);
inv[i]=qpow(i,MOD-2);
}
dep[1]=1;
dfs1(1);
dfs2(1,0,0);
for(int i=1;i<=q;++i){
int x,y;
cin>>x>>y;
int l=LCA(x,y);
if(x==l){
cout<<mod(E[y]-E[x])<<endl;
continue;
}
cout<<mod_plus(out[x],mod(preg[fa[x][0]]-preg[l]),mod(E[y]-inv[dep[l]]*preE[l]))<<endl;
}
return 0;
}

浙公网安备 33010602011771号