【JZOJ 5814】【NOIP提高A组模拟2018.8.14】 树

题目大意:

给定 \(Q\) 个询问,每个询问给出 \(u,v\),求从 \(u\) 走到 \(v\) 的期望步数。

正文:

\(f_i\) 表示第 \(i\) 个点到其父节点的期望步数,\(g_i\) 表示其父节点到第 \(i\) 个点的期望步数。则有:

\[f_x=\frac{1}{deg_x}+\sum_{y\in 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_{y\in son(fa(x))|y\ne x}\frac{g_x+1+f_y}{deg_{fa(x)}} \]

\(deg_x\) 表示节点 \(x\) 的度)

化简这两个式子:

\[\begin{aligned}f_x\cdot deg_x &=1+\sum_{y\in son(x)}f_x+1+f_y\\f_x\cdot deg_x&=dge_x+(deg_x-1)f_x+\sum_{y\in son(x)}f_y\\ f_x&=deg_x+\sum_{y\in son(x)}f_y\end{aligned} \]

\[\begin{aligned}g_x\cdot deg_{fa(x)}&=2+g_x+g_{fa(x)}+\sum_{y\in son(fa(x))|y\ne x}f_y\\ g_x\cdot deg_{fa(x)}&=deg_{fa(x}+(deg_{fa(x)}-1)g_x+g_{fa(x})+\sum_{y\in son(fa(x))|y\ne x}f_y\\g_x&=deg_{fa(x)}+g_{fa(x)}+\sum_{y\in son(fa(x))|y\ne x}f_y\end{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\n", ((ff[a] - ff[LCA] + g[b] - g[LCA]) % mod + mod) % mod);
	}
	return 0;
}

posted @ 2020-08-10 20:52  Jayun  阅读(98)  评论(0编辑  收藏  举报