根据博客的模拟,就可以知道做法和思想。
现在就是实现他。
例题 :hdu 2586
题意:m 个询问,x 到 y 的距离,我们的思想就是求出:x到根的距离+y到根的距离-2*(lca[ x ,y ])到跟的距离。
代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; const int max_edge=100005;//边数 const int max_Q=405;//问题 const int max_=40005;//节点 struct Tree{//树-邻接表 int to; int v; int next; }; struct Question{//离线-问题 int to; int id; int next; }; struct Tree a[max_edge];//树数组 struct Question b[max_];//问题数组 int N,M; int edge[max_];//边记录next int tot1,tot2; bool vis[max_];//标记数组 int st[max_Q],ed[max_Q];//问题的x和y int question[max_];//问题-记录next int fa[max_];//父节点 int dis[max_];//到根的距离 int LCA[max_Q];//问题的LCA void add_edge(int x,int y,int v)//建树 { a[++tot1].to=y; a[tot1].v=v; a[tot1].next=edge[x]; edge[x]=tot1; } void add_question(int x,int y,int id)//离线 { b[++tot2].to=y; b[tot2].id=id; b[tot2].next=question[x]; question[x]=tot2; } int find_fa(int x)//寻找父节点 { if(fa[x]==x) return x; return fa[x]=find_fa(fa[x]); } void Tarjan(int x) { fa[x]=x;//作为当前的根节点,将其父亲指向自己 vis[x]=1;//标记 for(int i=question[x];i;i=b[i].next)//寻找问题中与自己有关节点 { int go_to=b[i].to; if(vis[go_to]==true)//如果有关节点走过,记录LCA LCA[b[i].id]=find_fa(go_to); } for(int i=edge[x];i;i=a[i].next)//沿边遍历 { int go_to=a[i].to; if(vis[go_to]==false) { dis[go_to]=dis[x]+a[i].v;//更新距离 Tarjan(go_to);//递归遍历 fa[go_to]=x;//归并父节点 } } } int main() { int T; cin>>T;//测试组数 while(T--) { memset(vis,0,sizeof(vis)); memset(question,0,sizeof(question)); memset(edge,0,sizeof(edge)); memset(dis,0,sizeof(dis)); memset(LCA,0,sizeof(LCA)); tot1=0,tot2=0;//初始归零 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); } for(int i=0;i<M;i++) { int x,y; cin>>x>>y; add_question(x,y,i); add_question(y,x,i);//保证找有关点时不漏 st[i]=x,ed[i]=y;//记录问题的x,y } Tarjan(1); for(int i=0;i<M;i++) { int temp=dis[st[i]]+dis[ed[i]]-(2*dis[LCA[i]]);//结果 cout<<temp<<endl; } } }