CF123E Maze 题解

\(u\) 作为起点的概率为 \(q_u\) ,作为终点的概率为 \(p_u\)

题目给的代码可以看作一个从某个点开始,以它为根 dfs 到终点的步数,这启发我们直接考虑以每个点为根,到达所有可能终点的期望步数之和。

首先可以观察出几个性质:

假设当前的根为 \(x\),终点是 \(y\),那么从 \(x\) 开始走,考虑其中的一步。

  • 如果这一步进入了与 \(y\) 所在子树不同的一个子树,一定会把这个子树内的所有点遍历完才出来。假设进入了一个以 \(z\) 为根的子树,大小为 \(sz_z\),那么这个子树内的边数就是 \(sz_z-1\),所需步数即为 \(2(sz_z-1)+2=2sz_z\)
  • 如果走进了了 \(y\) 所在的子树,那么就不会再出来。

对于一个点,记 \(y\) 所在的子树的根为 \(u\)

由上面的性质可以知道,对于一个点,如果一个它的一个儿子 \(v \not=u\)\(u\) 之前被访问,那么答案就会加上 \(sz_v\)。而 \(v\)\(u\) 之前被访问的概率相当于给这个点的儿子随机一个排列,其中 \(v\)\(u\) 之前的概率。考虑对于每种 \(v\)\(u\) 之前的排列,swap(u,v) 之后就会得到一个 \(u\)\(v\) 之前的排列,所以概率是 \(\dfrac 12\)

接下来设 \(S\)\((x,fa_y)\) 这条路径上的点分叉出去的点集的并,那么 \(x\) 走到 \(y\) 的期望就是 \(\sum\limits_{u \in S} \dfrac{2sz_u}{2}\),对答案的贡献就是 \(q_xp_y\sum\limits_{u \in S}sz_u\)

接下来就考虑对于每个根 \(x\) 求出 \(p_y\sum\limits_{u \in S}sz_u\),先考虑以 \(1\) 为根。

\(f_u\) 表示以 \(u\) 为起点,到达 \(u\) 子树的的所有可能终点的期望步数之和,设 \(s=\sum\limits_{v \in son_u} sz_v=sz_u-1\)\(t_u=\sum\limits_{v\in Subtree_u} p_u\)

那么转移就是 \(f_u=\sum\limits_{v \in son_u} (s-sz_v+1)t_v+f_v\)

换根也非常容易,首先对于每个点的 \(\sum t_v\) 可以提前维护出来,这样子 \(s\) 的变化导致的答案增量也很容易算出,具体的转移可以见代码。

复杂度 \(O(n)\)

代码:

const int N=2e5+50;
int n,x[N],y[N],head[N],cnt;
ld sum[N],sumt[N],sz[N],t[N],p[N],q[N],f[N],g[N],ans;
struct edge{int to,nxt;}e[N<<1];
inline void addedge(int u,int v){e[++cnt]=(edge){v,head[u]},head[u]=cnt;}
void dfs1(int u,int fa)
{
	sz[u]=1,t[u]=p[u];
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs1(v,u),sz[u]+=sz[v],t[u]+=t[v];
		sum[u]+=sz[v],sumt[u]+=t[v];
	}
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		f[u]+=f[v]+(sum[u]-sz[v]+1)*t[v];
	}
}
void dfs2(int u,int fa)
{
	ans+=g[u]*q[u];
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		ld fu=g[u]-sz[v]*(1-p[u])-(n-1-2*sz[v]+1)*t[v]-f[v];
		g[v]=f[v]+(n-sz[v])*sumt[v]+(n-1-(n-sz[v])+1)*(1-t[v])+fu,dfs2(v,u);
	}
}
int main(void)
{
	n=read();int u,v,sumx=0,sumy=0;
	fr(i,2,n) u=read(),v=read(),addedge(u,v),addedge(v,u);
	fr(i,1,n) x[i]=read(),y[i]=read(),sumx+=x[i],sumy+=y[i];
	fr(i,1,n) q[i]=(ld)x[i]/(ld)sumx,p[i]=(ld)y[i]/(ld)sumy;
	dfs1(1,0),g[1]=f[1],dfs2(1,0);
	printf("%.10Lf\n",ans);
	return 0;
}
posted @ 2022-08-27 18:24  L_G_J  阅读(38)  评论(0编辑  收藏  举报