题目链接:
题意:给一棵树,求节点u到v的最短距离
弄一个dep[]数组,dep[u]表示u节点到根节点的深度,然后找到u和v节点的lca
dis[u]表示到根节点的距离,答案就是dis[u]+dis[v]-dis[lca]*2
在线算法
求出dfs序,然后u的dfs序到v的dfs序中深度最小的那个就是lca,用RMQ来维护
据说这道题数据很水,今天重新写的时候,我RMQ那里写彪了都过了,用另外几道题验过了,应该没毛病吧~
#include"bits/stdc++.h"
#define out(x) cout<<#x<<"="<<x
#define C(n,m) (m>n?0:(long long)fac[(n)]*invf[(m)]%MOD*invf[(n)-(m)]%MOD)
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
const int MOD=1e9+7;
int N,Q,n;//表示节点数,询问次数,dfs序长度
struct Edge
{
int t,v,nxt;
};
Edge E[maxn<<1];
int head[maxn];
int tot;
void AddEdge(int aa,int bb,int val)
{
E[++tot].t=bb;
E[tot].v=val;
E[tot].nxt=head[aa];
head[aa]=tot;
}
int dep[maxn],dis[maxn];//表示到根节点的深度和距离
int sa[maxn<<1],rnk[maxn<<1];//sa[i]表示dfs序是i的是原来哪个节点,rnk[i]表示i节点的dfs序是rnk[i]并且是第一次的序
int Time;//表示dfs序
void dfs(int u,int pre,int deep,int d)//弄出dfs序,以及每个节点到根节点的深度和距离
{
dep[u]=deep;
dis[u]=d;
sa[++Time]=u;//u节点进去的dfs序
if(rnk[u]==-1)rnk[u]=Time;
for(int i=head[u]; i!=-1; i=E[i].nxt)
{
int t=E[i].t;
int v=E[i].v;
if(t==pre)continue;
dfs(t,u,deep+1,d+v);
sa[++Time]=u;//u节点出来的dfs序
}
}
int dp[maxn<<1][20];
void RMQ()
{
n=N*2-1;
for(int i=1;i<=n;i++)dp[i][0]=sa[i];
for(int j=1;(1<<j)<=n;j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
int u=dp[i][j-1],v=dp[i+(1<<(j-1))][j-1];//数据很水这里写错了都能过
dp[i][j]=dep[u]<=dep[v]?u:v;
}
}
}
int LCA(int u,int v)//找u节点和v节点的lca
{
int L=rnk[u],R=rnk[v];
if(L>R)swap(L,R);//注意这里要保证L<=R
int k=0;
while((1<<(k+1))<=R-L+1)k++;
u=dp[L][k],v=dp[R-(1<<k)+1][k];//注意右端点要+1
return dep[u]<=dep[v]?u:v;
}
int main()
{
int T;
cin>>T;
while(T--)
{
memset(rnk,-1,sizeof rnk);
memset(head,-1,sizeof head);
tot=Time=0;
cin>>N>>Q;
for(int i=1; i<N; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
AddEdge(u,v,w);
AddEdge(v,u,w);
}
dfs(1,-1,0,0);
RMQ();
while(Q--)
{
int u,v;
scanf("%d%d",&u,&v);
int p=LCA(u,v);
cout<<dis[u]+dis[v]-dis[p]*2<<endl;
}
}
}