树
时间限制:2000MS内存限制:256000KB
题目描述
梦游中的你来到了一棵 N 个节点的树上. 你一共做了 Q 个梦, 每个梦需要你从点 u 走到 点 v 之后才能苏醒, 由于你正在梦游, 所以每到一个节点后,你会在它连出去的边中等概率地 选择一条走过去, 为了确保第二天能够准时到校, 你要求出每个梦期望经过多少条边才能苏 醒. 为了避免精度误差, 你要输出答案模10^9 + 7的结果.
HIT
输入
第一行两个整数分别代表 N 和 Q. 接下来 N-1 行, 每行两个整数 u, v 代表树中的一条边. 接下来 Q 行, 每行两个整数代表询问的 u,v.
输出
一共 Q 行, 每行一个整数代表答案
输入样例复制
4 2
1 2
2 3
3 4
1 4
3 4
输出样例复制
9
5
说明
Data Constraint 对于 20%的数据, N <= 10. 对于 40%的数据, N <= 1000. 另有 20%的数据, 保证给定的树是一条链. 对于 100%的数据, N <= 100000, Q <= 100000.
题解:设f[i]为从i结点走到i的父亲的期望长度,g[i]为i结点的父亲走到i的期望长度
对于f[i]有两种情况,一、先走到儿子再走到自己再走到父亲
二、直接走到父亲
化简可得
化简:两边同乘deg,右边的f[u]/g[u]移到左边发现系数剩下1
求出f[i],g[i]后,因为期望具有线性,所以做树上前缀和,fs[i]表示i到树根的期望值和,gs[i]同理
求出lca后ans=fs[i]-fs[lca]+gs[i]-gs[lca]
const
maxn=1000000;
p=1000000007;
var
n,q,kk,ans,x,y,ffa,i:longint;
e,last,next:array[0..maxn*2]of longint;
fa,f,g,sum:array[1..maxn]of int64;
ff:array[0..maxn,0..31]of int64;
v:array[1..maxn]of boolean;
du,dep,fs,gs:array[0..maxn]of int64;
lg:array[1..maxn]of int64;
mi:array[0..30]of int64;
procedure add(x,y:int64);
begin
inc(e[0]);
e[e[0]]:=y;
next[e[0]]:=last[x];
last[x]:=e[0];
end;
procedure build(x,y:longint);
var
i:longint;
begin
i:=last[x];
dep[x]:=y; if y>kk then kk:=y;
while i<>0 do
begin
inc(du[x]);
if not v[e[i]] then
begin
v[e[i]]:=true;
fa[e[i]]:=x;
build(e[i],y+1);
end;
i:=next[i];
end;
end;
procedure dfs1(x:longint);
var
i,go:longint;
begin
if (fa[x]<>0)and(du[x]=1) then
begin
f[x]:=1;
exit;
end;
v[x]:=true;
i:=last[x];
while i<>0 do
begin
go:=e[i];
if v[go] then
begin
i:=next[i];
continue;
end;
dfs1(e[i]);
sum[x]:=sum[x]+f[e[i]];
f[x]:=sum[x]+du[x];
i:=next[i];
end;
end;
procedure dfs2(x:longint);
var
i,go:longint;
begin
i:=last[x];v[x]:=true;
fs[x]:=fs[fa[x]]+f[x];
gs[x]:=gs[fa[x]]+g[x];
while i<>0 do
begin
go:=e[i];
if v[e[i]] then
begin
i:=next[i];
continue;
end;
g[go]:=g[x]+du[x]+sum[x]-f[go];
dfs2(e[i]);
i:=next[i];
end;
end;
procedure init;
var
i,j:longint;
begin
readln(n,q);
for i:=1 to n-1 do
begin
readln(x,y);
add(x,y);
add(y,x);
end;
v[1]:=true;
build(1,1);
fs[1]:=f[1];gs[1]:=g[1];
fillchar(v,sizeof(v),false);
dfs1(1);
fillchar(v,sizeof(v),false);
dfs2(1);
mi[0]:=1;
for i:=1 to 30 do
mi[i]:=mi[i-1]*2;
for i:=1 to maxn do
lg[i]:=trunc(ln(i)/ln(2));
for i:=1 to n do
ff[i,0]:=fa[i];
for j:=1 to lg[kk] do
for i:=1 to n do
ff[i,j]:=ff[ff[i,j-1],j-1];
end;
function lca(x,y:longint):longint;
var
t,i,j:longint;
begin
if dep[x]<dep[y] then
begin
t:=x;x:=y;y:=t;
end;
while dep[x]>dep[y] do
x:=ff[x,lg[dep[x]-dep[y]]];
if x=y then exit(x);
for i:=lg[dep[x]] downto 0 do
if ff[x,i]<>ff[y,i] then
begin
x:=ff[x,i];
y:=ff[y,i];
end;
lca:=fa[x];
end;
begin
init;
for i:=1 to q do
begin
readln(x,y);
ffa:=lca(x,y);
ans:=(fs[x]-fs[ffa]+gs[y]-gs[ffa])mod p;
writeln(ans);
end;
end.