题目描述
梦游中的你来到了一棵N个节点的树上. 你一共做了Q个梦, 每个梦需要你从点u走到点v之后才能苏醒, 由于你正在梦游, 所以每到一个节点后,你会在它连出去的边中等概率地选择一条走过去, 为了确保第二天能够准时到校, 你要求出每个梦期望经过多少条边才能苏醒. 为了避免精度误差, 你要输出答案模109+7的结果.
输入格式
第一行两个整数分别代表N和Q. 接下来N-1行, 每行两个整数u, v代表树中的一条边. 接下来Q行, 每行两个整数代表询问的u,v.
输出格式
一共Q行, 每行一个整数代表答案.
样例
tree.in
4 2
1 2
2 3
3 4
1 4
3 4
tree.out
9
5
数据范围
对于20%的数据, N <= 10.
对于40%的数据, N <= 1000.
另有20%的数据, 保证给定的树是一条链.
对于100%的数据, N <= 100000, Q <= 100000.
【解题报告】
这个小树什么的是骗你的。
我们定义
up[i]
为节点
i
到根节点的期望步数,
那么显然
u
到
我们接着定义
u[i]
为
i
节点走到它父亲的期望步数,
我们可以的得到
u[i]=2size[i]−1
d[i]=2n−2size[i]−1
一种证明方式http://blog.csdn.net/V5ZSQ/article/details/52314029
直接DP转移即可
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
#define N 100010
#define mod 1000000007
int n,q,cnt=-1,head[N];
struct Edge{int to,nxt;}e[N<<1];
int size[N];LL down[N],up[N];
void adde(int u,int v)
{
e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
e[++cnt].to=u;e[cnt].nxt=head[v];head[v]=cnt;
}
namespace LCA
{
int dis[N],ff[18][N];
void dfs(int p,int father)
{
dis[p]=dis[father]+1,ff[0][p]=father;
for(int i=head[p];~i;i=e[i].nxt)
{
int v=e[i].to;
if(v^father) dfs(v,p);
}
}
void da()
{
for(int j=1;(1<<j)<=n;++j)
for(int i=1;i<=n;++i)
ff[j][i]=ff[j-1][ff[j-1][i]];
}
int query(int x,int y)
{
if(dis[x]<dis[y]) x^=y^=x^=y;
int t=dis[x]-dis[y];
for(int i=0;i<=17;++i)
if(t&(1<<i)) x=ff[i][x];
if(x==y) return x;
for(int i=17;~i;--i)
if (ff[i][x]^ff[i][y]) x=ff[i][x],y=ff[i][y];
return ff[0][x];
}
}
namespace DP
{
void dfs1(int u,int fa)//size
{
size[u]=1;
for(int i=head[u];~i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa) continue;
dfs1(v,u);
size[u]+=size[v];
}
}
void dfs2(int u,int fa)//down&up(pre_sum!!!)
{
for(int i=head[u];~i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa) continue;
up[v]=2*size[v]-1+up[u];
down[v]=2*n-2*size[v]-1+down[u];
dfs2(v,u);
}
}
}
using namespace LCA;
using namespace DP;
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&q);
for(int i=1,u,v;i<n;++i)
{
scanf("%d%d",&u,&v);
adde(u,v);
}
dfs(1,1);
dfs1(1,1);
up[1]=0;down[1]=0;
dfs2(1,1);
da();
// for(int i=1;i<=n;++i) printf("%d %d\n",up[i],down[i]);
for(int i=1,u,v;i<=q;++i)
{
scanf("%d%d",&u,&v);
// printf("%d %d ",u,v);
int tmp=query(u,v);//printf(" %d ",tmp);
// printf("%d ",tmp);
long long ans=up[u]+down[v]-up[tmp]-down[tmp];
printf("%lld\n",ans%mod);
}
return 0;
}
/*
4 2
1 2
2 3
3 4
1 4
3 4
*/