仔细想一想:最近的公共祖先,其实,搜索时回朔,连通这两点,那深度最低肯定是最近的公共祖先啊。
那这样就可以变成RMQ问题了。
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; const int max_=41005; int ip,tot; struct Tree{//树 int to; int next; int v; }; struct Tree a[max_*2]; int first[max_];//第一次出现的位置 int edge[max_];//边记录next int de[max_*2];//深度 int id[max_*2];//遍历编号(包含回朔) int dis[max_];//到根的距离。 int dp[max_*2][25];//st表,记录的是下标 bool vis[max_];//标记数组 void add_edge(int x,int y,int v)//建树 { a[++ip].to=y; a[ip].v=v; a[ip].next=edge[x]; edge[x]=ip; } void dfs(int x,int deep)//dfs遍历 { if(vis[x]==0) { first[x]=tot;//记录第一次 vis[x]=1; } de[tot]=deep,id[tot++]=x; for(int i=edge[x];i;i=a[i].next) { int go_to=a[i].to; if(vis[go_to]) continue; int go_v=a[i].v; dis[go_to]=dis[x]+go_v;//跟新距离 dfs(go_to,deep+1); id[tot]=x,de[tot++]=deep; } } int Min(int x,int y)//寻找最小深度 { if(de[x]>de[y]) return y; else return x; } void RMQ_ST(int len) { for(int i=0;i<len;i++)//初始化 dp[i][0]=i; for(int j=1;(1<<j)<=len;j++) for(int i=0;i+(1<<j)-1<len;i++) { dp[i][j]=Min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } } int RMQ_question(int l,int r) { int k=0; while((1<<(k+1))<=r-l+1)k++; return Min(dp[l][k],dp[r-(1<<k)+1][k]); } void itin() { memset(vis,0,sizeof(vis)); memset(dis,0,sizeof(dis)); memset(edge,0,sizeof(edge)); tot=0; ip=0; } int main() { int T; cin>>T; while(T--) { itin(); int n,m; cin>>n>>m; for(int i=0;i<n-1;i++) { int x,y,v; cin>>x>>y>>v; add_edge(x,y,v); add_edge(y,x,v); } dfs(1,0); RMQ_ST(tot); for(int i=0;i<m;i++) { int u,v,k; cin>>u>>v; if(first[u]>first[v])//先出现的为左 { k=RMQ_question(first[v],first[u]); } else k=RMQ_question(first[u],first[v]); int temp=dis[u]+dis[v]-(2*dis[id[k]]); cout<<temp<<endl; } } return 0; }