树
题目大意
给你一棵有n个节点的树,以及m个询问,每个询问需要你回答一个点到另一个点要经过的期望边数
输入样例
4 2
1 2
2 3
3 4
1 4
3 4
输出样例
9
5
数据范围
对于 20%20\%20%的数据,N⩽10.N \leqslant 10.N⩽10.
对于 40%40\%40%的数据,N⩽1000.N \leqslant 1000.N⩽1000.
另有 20%20\%20%的数据, 保证给定的树是一条链.
对于 100%100\%100%的数据, N⩽100000,Q⩽100000.N \leqslant 100000, Q \leqslant 100000.N⩽100000,Q⩽100000.
解题思路
树上两点之间的距离要先求lcalcalca,然后可以通过前缀和来得出两点到lcalcalca距离
对于前缀和我们要先得出某个点到父亲节点和儿子节点的期望距离
我们设
degxdeg_xdegx为点xxx的度数
dp1xdp1_xdp1x为点xxx到父亲节点的期望距离
dp2xdp2_xdp2x为点xxx的父亲节点到点x的期望距离
我们先算dp1dp1dp1
叶子结点到父亲节点的期望距离为1,因为只能往上
对于不是叶子结点的点xxx
它直接到父亲节点的期望是1degx\frac{1}{deg_x}degx1(1degx\frac{1}{deg_x}degx1的概率走这条边)
他到子节点i再回来再到父亲节点的期望是1+dp1i+dp1xdegx\frac{1+dp1_i+dp1_x}{deg_x}degx1+dp1i+dp1x
所以可以得到以下式子
dp1x=1degx+∑i∈sonx1+dp1i+dp1xdegxdp1_x=\frac{1}{deg_x}+\sum_{i\in son_x}\frac{1+dp1_i+dp1_x}{deg_x}dp1x=degx1+i∈sonx∑degx1+dp1i+dp1x
化简式子
dp1x=1degx+degx−1degx+(degx−1)dp1xdegx+∑i∈sonxdp1idegxdp1_x=\frac{1}{deg_x}+\frac{deg_x-1}{deg_x} + \frac{(deg_x-1)dp1_x}{deg_x} + \sum_{i\in son_x}\frac{dp1_i}{deg_x}dp1x=degx1+degxdegx−1+degx(degx−1)dp1x+i∈sonx∑degxdp1i
移项
dp1xdegxdegx−(degx−1)dp1xdegx=1degx+degx−1degx+∑i∈sonxdp1idegx\frac{dp1_x deg_x}{deg_x}-\frac{(deg_x-1)dp1_x}{deg_x}=\frac{1}{deg_x}+\frac{deg_x-1}{deg_x} + \sum_{i\in son_x}\frac{dp1_i}{deg_x}degxdp1xdegx−degx(degx−1)dp1x=degx1+degxdegx−1+i∈sonx∑degxdp1i
化简
dp1xdegx=1degx+degx−1degx+∑i∈sonxdp1idegx\frac{dp1_x}{deg_x}=\frac{1}{deg_x}+\frac{deg_x-1}{deg_x} + \sum_{i\in son_x}\frac{dp1_i}{deg_x}degxdp1x=degx1+degxdegx−1+i∈sonx∑degxdp1i
同乘degxdeg_xdegx
dp1x=degx+∑i∈sonxdp1idp1_x=deg_x+ \sum_{i\in son_x}dp1_idp1x=degx+i∈sonx∑dp1i
求出dp1后我们来求dp2
父亲节点直接到目标子节点的期望是1degfa\frac{1}{deg_{fa}}degfa1
父亲节点先到父亲节点的父亲节点然后回来再到目标子节点的期望是1+dp2fa+dp2xdegfa\frac{1+dp2_{fa}+dp2_x}{deg_{fa}}degfa1+dp2fa+dp2x
父亲节点先到其他子节点再回来再到目标子节点的期望是1+dp1i+dp2xdegfa\frac{1+dp1_i+dp2_x}{deg_{fa}}degfa1+dp1i+dp2x
所以我们得到式子
dp2x=1degfa+1+dp2fa+dp2xdegfa+∑i∈sonfa∣i≠x1+dp1i+dp2xdegfadp2_x=\frac{1}{deg_{fa}} + \frac{1+dp2_{fa}+dp2_x}{deg_{fa}}+\sum_{i\in son_{fa}|i\neq x}\frac{1+dp1_i+dp2_x}{deg_{fa}}dp2x=degfa1+degfa1+dp2fa+dp2x+i∈sonfa∣i=x∑degfa1+dp1i+dp2x
化简式子
dp2x=1degfa+1+dp2fadegfa+dp2xdegfa+degfa−2degfa+(degfa−2)dp2xdegfa+∑i∈sonfa∣i≠xdp1idegfadp2_x=\frac{1}{deg_{fa}} + \frac{1+dp2_{fa}}{deg_{fa}} + \frac{dp2_x}{deg{fa}}+\frac{deg_{fa}-2}{deg_{fa}}+\frac{(deg_{fa}-2)dp2_x}{deg_{fa}}+\sum_{i\in son_{fa}|i\neq x}\frac{dp1_i}{deg_{fa}}dp2x=degfa1+degfa1+dp2fa+degfadp2x+degfadegfa−2+degfa(degfa−2)dp2x+i∈sonfa∣i=x∑degfadp1i
移项
dp2xdegfadegfa−dp2xdegfa−(degfa−2)dp2xdegfa=1degfa+1+dp2fadegfa+degfa−2degfa+∑i∈sonfa∣i≠xdp1idegfa\frac{dp2_x deg_{fa}}{deg{fa}} - \frac{dp2_x}{deg{fa}} - \frac{(deg_{fa}-2)dp2_x}{deg_{fa}}=\frac{1}{deg_{fa}} + \frac{1+dp2_{fa}}{deg_{fa}} +\frac{deg_{fa}-2}{deg_{fa}}+\sum_{i\in son_{fa}|i\neq x}\frac{dp1_i}{deg_{fa}}degfadp2xdegfa−degfadp2x−degfa(degfa−2)dp2x=degfa1+degfa1+dp2fa+degfadegfa−2+i∈sonfa∣i=x∑degfadp1i
合并
dp2xdegfa=1degfa+1+dp2fadegfa+degfa−2degfa+∑i∈sonfa∣i≠xdp1idegfa\frac{dp2_x}{deg{fa}}=\frac{1}{deg_{fa}} + \frac{1+dp2_{fa}}{deg_{fa}} +\frac{deg_{fa}-2}{deg_{fa}}+\sum_{i\in son_{fa}|i\neq x}\frac{dp1_i}{deg_{fa}}degfadp2x=degfa1+degfa1+dp2fa+degfadegfa−2+i∈sonfa∣i=x∑degfadp1i
同乘degfadeg_{fa}degfa
dp2x=dp2fa+degfa+∑i∈sonfa∣i≠xdp1idp2_x=dp2_{fa} +deg_{fa}+\sum_{i\in son_{fa}|i\neq x}dp1_idp2x=dp2fa+degfa+i∈sonfa∣i=x∑dp1i
根据dp1xdp1_xdp1x的式子化简该式子
∵degfa+∑i∈sonfa∣i≠xdp1i=degfa+∑i∈sonfadp1i−dp1x=dp1fa−dp1x∴dp2x=dp2fa+dp1fa−dp1x\begin{aligned} \because deg_{fa}+\sum_{i\in son_{fa}|i\neq x}dp1_i & =deg_{fa}+\sum_{i\in son_{fa}}dp1_i-dp1_x \\ & =dp1_{fa}-dp1_x\end{aligned} \\ \therefore dp2_x=dp2_{fa} +dp1_{fa}-dp1_x∵degfa+i∈sonfa∣i=x∑dp1i=degfa+i∈sonfa∑dp1i−dp1x=dp1fa−dp1x∴dp2x=dp2fa+dp1fa−dp1x
然后求前缀和,再求lcalcalca
然后求aaa到lcalcalca再到bbb的期望步数即可
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define wyc 1000000007
using namespace std;
ll n, m, x, y, z, g, tot, dep[110010], deg[110010], dp1[110010], dp2[110010], head[110010], f[110010][20];
struct rec
{ll to, next;
}a[210020];
void add(ll x, ll y)
{a[++tot].to = y;a[tot].next = head[x];head[x] = tot;return;
}
void dfs1(ll x, ll fa)//记录dp1
{f[x][0] = fa;//记录父亲dep[x] = dep[fa] + 1;//求深度dp1[x] = deg[x];for (int i = head[x]; i; i = a[i].next)if (a[i].to != fa){dfs1(a[i].to, x);dp1[x] = (dp1[x] + dp1[a[i].to]) % wyc;}return;
}
void dfs2(ll x, ll fa)//求dp2
{for (int i = head[x]; i; i = a[i].next)if (a[i].to != fa){dp2[a[i].to] = (dp1[x] - dp1[a[i].to] + dp2[x]) % wyc;dfs2(a[i].to, x);}return;
}
void dfs3(ll x, ll fa)//前缀和
{for (int i = head[x]; i; i = a[i].next)if (a[i].to != fa){dp1[a[i].to] = (dp1[a[i].to] + dp1[x]) % wyc;dp2[a[i].to] = (dp2[a[i].to] + dp2[x]) % wyc;dfs3(a[i].to, x);} return;
}
ll lca(ll x, ll y)
{if (dep[x] < dep[y]) g = x, x = y, y = g;for (int i = 16; i >= 0; --i)if (dep[x] - (1<<i) >= dep[y]) x = f[x][i];for (int i = 16; i >= 0; --i)if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];return x == y?x:f[x][0];
}
int main()
{scanf("%lld%lld", &n, &m);for (int i = 1;i < n; ++i){scanf("%lld%lld", &x, &y);deg[x]++;deg[y]++;add(x, y);add(y, x);}dfs1(1, 1);dfs2(1, 1);dfs3(1, 1); for (int j = 1; j <= 16; ++j)for (int i = 1; i <= n; ++i)f[i][j] = f[f[i][j - 1]][j - 1];for (int i = 1; i <= m; ++i){scanf("%lld%lld", &x, &y);z = lca(x, y);printf("%lld\n", ((wyc + dp1[x] - dp1[z]) % wyc + (wyc + dp2[y] - dp2[z]) % wyc) % wyc);}return 0;
}