18 篇文章 0 订阅
12 篇文章 0 订阅


这道题虽然已经做过多次,但比赛时还是不会做。
看了题解之后,我觉得要是我自己想肯定是做不出来的 qwq

————————————————————————————————

f[i]表示i到fath[i]的期望步数,g[i]表示fath[i]到i的期望步数

仔 细 想 想 这 个 做 法 挺 显 然 的 , 因 为 要 输 入 多 组 u , v , 所 以 只 有 这 样 才 能 在 l o g 的 时 间 里 求 出 期 望 长 度 仔细想想这个做法挺显然的,因为要输入多组u,v,所以只有这样才能在log的时间里求出期望长度 uvlog
推一下式子
f [ i ] = ( 1 / d e g [ i ] ) + ( 1 / d e g [ i ] ) ∗ ∑ v ∈ s o n [ i ] ( 1 + f [ v ] + f [ s ] ) f[i]=(1/deg[i])+(1/deg[i])*\sum{v∈son[i]}(1+f[v]+f[s]) f[i]=(1/deg[i])+(1/deg[i])vson[i](1+f[v]+f[s])
g [ i ] = ( 1 / d e g [ f a t h [ i ] ] ) + ( 1 / d e g [ f a t h [ i ] ] ) ∗ ∑ v ∈ s o n [ f a t h [ i ] ] , v ! = i ( 1 + f [ v ] + g [ s ] ) + ( 1 / d e g [ f a t h [ i ] ] ) ∗ ( 1 + g [ f a [ s ] ] + g [ s ] ) g[i]=(1/deg[fath[i]])+(1/deg[fath[i]])*\sum{v∈son[fath[i]],v!=i}(1+f[v]+g[s])+(1/deg[fath[i]])*(1+g[fa[s]]+g[s]) g[i]=(1/deg[fath[i]])+(1/deg[fath[i]])vson[fath[i]],v!=i(1+f[v]+g[s])+(1/deg[fath[i]])(1+g[fa[s]]+g[s])
推一推式子,得到

g[v]=deg[s]+g[s]+sum[s]-f[v]
f[s]=deg[s]+sum[s]
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e5+5;
ll mod=1e9+7;
ll ksm(ll x,ll pow){
 	ll ans=1,res=x;
 	while(pow){
 		if(pow&1) ans=ans*res%mod;
 		res=res*res%mod;
 		pow>>=1;
 	}
 	return ans;
}
ll ny(ll x){return ksm(x,mod-2);}
int n,Q,head[N],cnt=0;
struct edge{
	int link,v;
}q[N<<1];
void put(int x,int y){
	q[++cnt].v=y;
	q[cnt].link=head[x];
	head[x]=cnt;
}
int f[N],g[N],deg[N],sum[N],fath[N];
void dfs(int s,int fa){
     sum[s]=0;
	for(int i=head[s];i;i=q[i].link){
		int v=q[i].v;
		if(v==fa) continue;
		fath[v]=s;
		deg[s]++;deg[v]=1;
		dfs(v,s);
		sum[s]=(sum[s]+f[v])%mod;
	}
	f[s]=(deg[s]+sum[s])%mod;
}
void dfs2(int s,int fa){
	for(int i=head[s];i;i=q[i].link){
		int v=q[i].v;
		if(v==fa) continue;
		g[v]=((deg[s]+g[s])%mod+(1ll*sum[s]-f[v]+mod)%mod)%mod;
		dfs2(v,s);
	}
}
int ff[N][21],ss[N][21][2],lg[N],depth[N];
void get_f(int s,int fa){
	for(int i=head[s];i;i=q[i].link){
		int v=q[i].v;
		if(v==fa) continue;
		depth[v]=depth[s]+1;
	    ff[v][0]=s,ss[v][0][0]=f[v],ss[v][0][1]=g[v];
		for(int j=1;j<=lg[depth[v]];j++){
	    	ff[v][j]=ff[ff[v][j-1]][j-1];
	    	ss[v][j][0]=(ss[v][j-1][0]+ss[ff[v][j-1]][j-1][0])%mod;
	    	ss[v][j][1]=(ss[v][j-1][1]+ss[ff[v][j-1]][j-1][1])%mod;
	    }
	    get_f(v,s);
	}
}
ll ans=0;
void find(int x,int y){
	if(depth[x]<depth[y]){
		int jp=lg[depth[y]-depth[x]];
		 while(depth[x]!=depth[y]){
		 	 ans=(ans+ss[y][jp][1])%mod;	
			  y=ff[y][jp];
			  jp=lg[depth[y]-depth[x]];
		 }
		 if(x==y) return;
	}
	if(depth[y]<depth[x]){
		int jp=lg[depth[x]-depth[y]];
		 while(depth[x]!=depth[y]){
		 	 ans=(ans+ss[x][jp][0])%mod;	
			  x=ff[x][jp];
			  jp=lg[depth[x]-depth[y]];
		 }
		 if(x==y) return;
	}
	int up=lg[depth[x]];
	for(int i=up;i>=0;i--){
		if(ff[x][i]!=ff[y][i]){
			ans=(ans+ss[x][i][0])%mod;
			ans=(ans+ss[y][i][1])%mod;
			x=ff[x][i],y=ff[y][i];
		}
	}
	ans=(ans+ss[x][0][0])%mod;
	ans=(ans+ss[y][0][1])%mod;
}
int main(){
	scanf("%d%d",&n,&Q);
    for(int i=1;i<n;i++){
    	int u,v;
    	scanf("%d%d",&u,&v);
    	put(u,v),put(v,u);
    }
    lg[1]=0;
    for(int i=2;i<=n;i++){lg[i]=lg[i>>1]+1;}
    dfs(1,0),f[1]=0;
    g[1]=0,dfs2(1,0);
    get_f(1,0);
    while(Q--){
    	int u,v;
    	ans=0;
    	scanf("%d%d",&u,&v);
    	if(u==v){
    		puts("0");
    		continue;
    	}
		find(u,v);
		printf("%lld\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值