题目大意:
给定 (Q) 个询问,每个询问给出 (u,v),求从 (u) 走到 (v) 的期望步数。
正文:
设 (f_i) 表示第 (i) 个点到其父节点的期望步数,(g_i) 表示其父节点到第 (i) 个点的期望步数。则有:
[f_x=frac{1}{deg_x}+sum_{yin son(x)}frac{1+f_x+f_y}{deg_x} \ g_x=frac{1}{deg_{fa(x)}}+frac{1+g_x+g_{fa(x)}}{deg_{fa(x)}}+sum_{yin son(fa(x))|y
e x}frac{g_x+1+f_y}{deg_{fa(x)}}
]
((deg_x) 表示节点 (x) 的度)
化简这两个式子:
[egin{aligned}f_xcdot deg_x &=1+sum_{yin son(x)}f_x+1+f_y\f_xcdot deg_x&=dge_x+(deg_x-1)f_x+sum_{yin son(x)}f_y\ f_x&=deg_x+sum_{yin son(x)}f_yend{aligned}
]
[egin{aligned}g_xcdot deg_{fa(x)}&=2+g_x+g_{fa(x)}+sum_{yin son(fa(x))|y
e x}f_y\ g_xcdot deg_{fa(x)}&=deg_{fa(x}+(deg_{fa(x)}-1)g_x+g_{fa(x})+sum_{yin son(fa(x))|y
e x}f_y\g_x&=deg_{fa(x)}+g_{fa(x)}+sum_{yin son(fa(x))|y
e x}f_yend{aligned}
]
用树形DP求出 (f,g),用LCA求出距离。
代码:
void dfs (int u, int fa)
{
for (int i = head[u]; i; i = next[i])
deg[u]++;
ff[u] = deg[u];
for (int i = head[u]; i; i = next[i])
{
int v = to[i];
if (v == fa) continue;
dfs(v, u);
ff[u] += ff[v];
ff[u] %= mod;
}
}
void dfs1 (int u, int fa)
{
int sum = deg[u];
for (int i = head[u]; i; i = next[i])
{
int v = to[i];
if(v == fa) {sum += g[u];sum%=mod;continue;}
sum += ff[v];
sum %= mod;
}
for (int i = head[u]; i; i = next[i])
{
int v = to[i];
if(v == fa) continue;
g[v] = ((sum - ff[v]) % mod + mod) % mod;
dfs1(v, u);
}
}
void dfs2 (int u, int fa)
{
d[u] = d[fa] + 1;
f[u][0] = fa;
for (int i = head[u]; i; i = next[i])
{
int v = to[i];
if(v == fa) continue;
ff[v] += ff[u];
ff[v] %= mod;
g[v] += g[u];
g[v] %= mod;
dfs2 (v, u);
}
}
int lca (int x, int y)
{
if (d[x] > d[y])
{
int t = x;
x = y;
y = t;
}
for (int i = num; i >= 0; i--)
if (d[f[y][i]] >= d[x])
y = f[y][i];
if (x == y) return x;
for (int i = num; i >= 0; i--)
if (f[x][i] != f[y][i])
{
x = f[x][i];
y = f[y][i];
}
return f[x][0];
}
int main()
{
scanf ("%d%d", &n, &m);
num = (int) (log2(n)) + 1;
for (int i = 1; i < n; i++)
{
int u, v;
scanf ("%d%d", &u, &v);
Add(u, v), Add(v, u);
}
dfs(1, 0);
dfs1(1, 0);
dfs2(1, 0);
for (int i = 1; i <= 19; i++)
for (int j = 1; j <= n; j++)
f[j][i] = f[f[j][i - 1]][i - 1];
for (int i = 1; i <= m; i++)
{
int a, b;
scanf ("%d%d", &a, &b);
int LCA = lca(a, b);
printf("%d
", ((ff[a] - ff[LCA] + g[b] - g[LCA]) % mod + mod) % mod);
}
return 0;
}