链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
题意:n个村庄构成一棵无根树,q次询问,求任意两个村庄之间的最短距离
思路:求出两个村庄的LCA,dis[ i ] 表示结点 i 到树根的距离,那么任意两点u,v的最短距离就是dis[ u ] - dis [LCA] + dis [ v ] - dis[ LCA ]。代码是用tarjan做的,算是模板,记录一下。
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<queue> 7 using namespace std; 8 const int maxn = 40005; 9 struct node{//询问的结点x,y 10 int x,y; 11 int lca; 12 }query[maxn]; 13 struct e{//建边 14 int to; 15 int val; 16 }; 17 int dis[maxn]; 18 vector<e> G[maxn]; 19 vector<int> Q[maxn]; 20 bool vis[maxn]; 21 int N; 22 int fa[maxn]; 23 void init(){//初始化父亲结点 24 for(int i = 0;i<maxn;i++) fa[i] = i; 25 } 26 int find(int x){//并查集find函数 27 if(x == fa[x]) return x; 28 return fa[x] = find(fa[x]); 29 } 30 void tarjan(int cur){ 31 vis[cur] = true;//标记cur已访问过 32 for(auto q:Q[cur]){//遍历包含cur结点的询问 33 if(query[q].x == cur){ 34 if(vis[query[q].y]) {//若x == cur且y已经被访问过,搜y的祖先,就是其LCA 35 query[q].lca = find(query[q].y); 36 } 37 } 38 else{ 39 if(vis[query[q].x]){//若y == cur且x已经被访问过,搜x的祖先,就是其LCA 40 query[q].lca = find(query[q].x); 41 } 42 } 43 } 44 for(auto e:G[cur]){//遍历cur结点的儿子结点 45 int v = e.to , len = e.val ; 46 if(vis[v]) continue; 47 dis[v] = dis[cur] + len;//dis记录cur到root的距离 48 tarjan(v); 49 fa[v] = cur; //设置cur结点子节点的父亲为cur 50 } 51 } 52 int main(){ 53 int t;scanf("%d",&t); 54 while(t--){ 55 scanf("%d",&N); 56 int q; 57 memset(vis,0,sizeof(vis)); 58 init(); 59 for(int i = 0;i<maxn;i++) {//初始化 60 Q[i].clear() ,G[i].clear() ; 61 query[i].lca = 0,query[i].x = 0,query[i].y = 0; 62 } 63 scanf("%d",&q); 64 for(int i = 1;i<=N-1;i++){ 65 int u,v,k; 66 scanf("%d%d%d",&u,&v,&k); 67 G[u].push_back({v,k}); //建图 68 G[v].push_back({u,k}); 69 } 70 for(int i = 1;i<=q;i++){ 71 scanf("%d%d",&query[i].x ,&query[i].y ); 72 Q[query[i].x ].push_back(i); 73 Q[query[i].y ].push_back(i); //离线存储所有询问 ,i为标号 74 } 75 tarjan(1); 76 for(int i = 1;i<=q;i++){ 77 int LCA = query[i].lca ; 78 int ans = dis[query[i].x ] + dis[query[i].y ] - 2*dis[LCA];//输出所有的询问 79 printf("%d ",ans); 80 } 81 } 82 return 0; 83 }