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\) 写出转移:

\[down_x=\frac{1}{deg_f}\bigg(1+\sum_{v\in son_f,v\not=x}\big(1+out_v+\frac{1}{dep_f}\sum_{y\in A_f}(E_f-E_y)+down_x\big)\bigg) \]

解方程则有

\[down_x=deg_f+\frac{deg_f-1}{dep_f}\sum_{y\in A_f}(E_f-E_y)+\sum_{v\in son_f,v\not=x}out_v \]

再求 \(out_x\)

如果 \(x\) 是叶子,则有 \(out_x=1\) ,因为我们要把往上跳的代价算上。

否则它将等概率地从每个子树跳出来,根据我们转化后的问题,从子树跳到 \(x\) 这一步的代价一定是 \(0\),而它有 \(\frac{1}{dep_x}\) 的概率停住,如果停住则回到了原来的问题;否则有 \(\frac{dep_x-1}{dep_x}\) 概率跳出去,然而这个向上跳的代价是 \(0\)

\[out_x=\frac{1}{deg_x}\sum_{v\in son_x}\bigg(1+out_v+\frac{1}{dep_x}out_x+\frac{dep_x-1}{dep_x}·0\bigg) \]

解方程得出:

\[out_x=\frac{dep_x}{dep_x-1}\bigg(1+\frac{1}{deg_x}\sum_{v\in son_x}out_v\bigg) \]

那怎么求答案呢?

\(\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\)

也就是:

\[ans=out_x+g_{f,l}+\frac{1}{dep_l}\sum_{v\in A_l}(E_y-E_v) \]

为什么不是 \(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;
}
posted @ 2026-07-31 15:23  司马只因锥  阅读(8)  评论(0)    收藏  举报