题意
给你一棵树和每条边的权值,m次询问,求任两点间距离,LCA+tarjin裸题。
思路
能用的算法大概也很多吧,但是就为了练一手LCA+tarjin我就来做这题了,够裸了,还能验板子233。
这个算法主要是用到了并查集,找LCA,在找到询问对的时候存下LCA。然后最后利用公式结合tarjin得来的距离和LCA直接得出答案。
所以说此处我们进行遍历的目的有两个——1.找到目标点对的LCA,2.找到所有点距离初始点的距离。最后的答案是通过以上我们得到的信息算出来的。
该题详情请见代码。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=4e4+5; 4 typedef pair<int,int> PII; 5 struct edge{ 6 int to,len; 7 }; 8 struct askedge{ 9 int from,to,lca; 10 }ae[300];//询问对 11 int n,m; 12 vector<edge> G[N];//邻接表 13 vector<PII> pp[N];//存储每个点相对的询问点 14 int dist[N];//距离 15 int fa[N];//并查集 16 int Find(int x) 17 { 18 if(x==fa[x]) return x; 19 else return fa[x]=Find(fa[x]); 20 } 21 void Union(int x,int y) 22 { 23 x=Find(x);y=Find(y); 24 if(x!=y) fa[y]=x; 25 } 26 void dfs(int now) 27 { 28 fa[now]=now;//初始化,分离成init()函数也没问题 29 for(int i=0;i<pp[now].size();i++)//看当前这个点有没有它的点对已经被搜索到 30 { 31 PII &v=pp[now][i]; 32 if(dist[v.first]!=-1){ 33 ae[v.second].lca=fa[v.first];//如果存在,他们的lca就是当前点对象的爸爸 34 } 35 } 36 for(int i=0;i<G[now].size();i++)//遍历搜索 37 { 38 edge &v=G[now][i]; 39 if(dist[v.to]==-1) 40 { 41 dist[v.to]=dist[now]+v.len; 42 dfs(v.to); 43 Union(now,v.to);//回溯时合并 44 } 45 } 46 } 47 int main() 48 { 49 int T; 50 scanf("%d",&T); 51 while(T--) 52 { 53 scanf("%d%d",&n,&m); 54 for(int i=0;i<=n;i++)//初始化 55 { 56 pp[i].clear(); 57 G[i].clear(); 58 } 59 for(int i=0;i<=m;i++) 60 pp[i].clear(); 61 for(int i=0,u,v,len;i<n-1;i++)//读入图 62 { 63 scanf("%d%d%d",&u,&v,&len); 64 G[u].push_back(edge {v,len}); 65 G[v].push_back(edge {u,len}); 66 } 67 for(int i=1;i<=m;i++)//读入询问 68 { 69 int u,v; 70 scanf("%d%d",&u,&v); 71 pp[u].push_back(make_pair(v,i)); 72 pp[v].push_back(make_pair(u,i)); 73 ae[i]={u,v,-1}; 74 } 75 memset(dist,-1,sizeof(dist)); 76 dist[1]=0; 77 dfs(1);//开始tarjin 78 for(int i=1;i<=m;i++)//对每次询问输出答案 79 { 80 askedge &u=ae[i]; 81 printf("%d ",dist[u.from]+dist[u.to]-2*dist[u.lca]);//公式 82 } 83 } 84 return 0; 85 }