【题目描述】
有一棵n个点的树。
有m次询问,每次给定起点s和终点t,会从s走到t。由于眼神不好,它会按如下方式走路:
(1)初始时在s,如果到达t就立刻停止;
(2)如果相邻点中存在离s更远且没走过的点,那么等概率随机一个满足条件的点走过去;
(3)否则,往s所在方向走一步。
你需要求出期望经过多少个点(包括s和t)。一个点被多次经过只计算一次。
【输入数据】
第一行两个整数n,m,接下来n-1行每行两个整数u,v表示一条边,接下来m行每行两个整数s,t表示一组询问。
【输出数据】
每组询问输出一行一个实数表示答案,保留一位小数。
【样例输入】
3 3
1 2
2 3
1 2
1 3
2 3
【样例输出】
2.0
3.0
2.5
【数据范围】
对于10%的数据,n,m<=7。
对于30%的数据,n,m<=100。
对于60%的数据,n<=5000。
对于100%的数据,1<=n,m<=500000,s!=t。
题解:首先不难发现,如果某一步是朝着t走的,那么一定不会走回来了;否则,一定会把整棵子树走完再回到当前点。走到一个s到t路径上的点时,会随机选择一个儿子走下去,这等价于随机一个儿子们的排列,然后按这个顺序走。那么s到t的路径上所有点显然一定会走到,以s为根时t子树中的点显然走不到,而其它点都有1/2的概率会走到。时间复杂度O(nlogn+m)。
考场时想到了除了在路径上的点,其他的点连接的点都有1/2的概率走到。但是,想到的都是些线段树修改什么的感觉有点假很复杂,肯定又是一百多行的代码,没有想下去。
其实就是把在路径上的点赋值为1,余下的连接的点赋值为1/2。分在同一条链上的情况,和在两颗子树的情况,重点在于求那些点是不需要走的。详见代码。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=10000000;
int n,m;
vector< int > a[MAXN];
int p[MAXN][25],deep[MAXN],size[MAXN],f;
double ans[MAXN];
void dfs(int x,int dep)
{
for(int i=1;i<=22;i++)
p[x][</