给一棵树,若干个查询,每次查询树上两点的距离。第一道LCA的题..完全是裸的,把查询存起来,直接tarjan就可以。res[i][0],res[i][1],res[i][2]分别表示第i个查询的起点,终点和起点终点的最近公共祖先,记dis[x]为x到根节点的距离,那么dis(0,1)就是dis[0]+dis[1]-2*dis[2].
#include <iostream> #include <cstdio> #include <algorithm> #include <memory.h> #include <cmath> using namespace std; typedef long long ll; const int maxn=40000+40; struct node { int w,v; int next; }edge[maxn<<1],query[500]; bool vis[maxn]; int g[maxn],gg[maxn]; int res[maxn][3]; int m,n,k,p,q; int en,eq; int test; int fa[maxn]; int dis[maxn]; int find(int x) { if (x!=fa[x]) return fa[x]=find(fa[x]); return x; } void tarjan(int u) { vis[u]=true; fa[u]=u; for (int j=gg[u]; j!=-1; j=query[j].next) { if (vis[query[j].v]) { res[query[j].w][2]=find(query[j].v); } } for (int j=g[u]; j!=-1; j=edge[j].next) { if (!vis[edge[j].v]) { dis[edge[j].v]=dis[u]+edge[j].w; tarjan(edge[j].v); fa[edge[j].v]=u; } } } int main() { // freopen("in.txt","r",stdin); scanf("%d",&test); while (test--) { memset(vis,false,sizeof vis); memset(dis,0,sizeof dis); scanf("%d",&n); scanf("%d",&m); memset(g,-1,sizeof g); memset(gg,-1,sizeof gg); en=eq=0; int x,y,z; for (int i=1; i<n; i++) { scanf("%d%d%d",&x,&y,&z); edge[en].w=z; edge[en].v=y; edge[en].next=g[x]; g[x]=en; en++; edge[en].w=z; edge[en].v=x; edge[en].next=g[y]; g[y]=en; en++; } for (int i=1; i<=m; i++) { scanf("%d%d",&x,&y); query[eq].v=y; query[eq].w=i; query[eq].next=gg[x]; gg[x]=eq; eq++; query[eq].v=x; query[eq].w=i; query[eq].next=gg[y]; gg[y]=eq; eq++; res[i][0]=x; res[i][1]=y; } dis[1]=0; tarjan(1); for (int i=1; i<=m; i++) { cout<<dis[res[i][0]]+dis[res[i][1]]-2*dis[res[i][2]]<<endl; } } return 0; }