链接:
How far away ?
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 11204 Accepted Submission(s): 4079
Problem Description
There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can‘t visit a place twice) between every two houses. Yout task is to answer all these curious people.
Input
First line is a single integer T(T<=10), indicating the number of test cases.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
Output
For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3
2 2
1 2 100
1 2
2 1
Sample Output
10
25
100
100
一个村子里有n个房子,这n个房子用n-1条路连接起来,接下了有m次询问,每次询问两个房子a,b之间的距离是多少。
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <queue> #include <stack> #include <map> #include <algorithm> #include <set> using namespace std; typedef long long ll; typedef unsigned long long Ull; #define MM(a,b) memset(a,b,sizeof(a)); const double eps = 1e-10; const int inf =0x7f7f7f7f; const double pi=acos(-1); const int maxn=40000; struct Edge{ int to,w; Edge(int a,int b):to(a),w(b){}; Edge(){}; }e[maxn+10]; struct node{ int to,id; }; vector<Edge> G[maxn+10]; vector<node> mp[maxn+10]; int vis[maxn+10],query[maxn+10][4],par[maxn+10],dis[maxn+10]; int findr(int u) { if(par[u]!=u) par[u]=findr(par[u]); return par[u]; } void unite(int u,int v) { int ru=findr(u); int rv=findr(v); if(ru!=rv) par[rv]=ru; } void tarjan(int u,int val) { vis[u]=1; dis[u]=val; for(int i=0;i<mp[u].size();i++) { int v=mp[u][i].to; int id=mp[u][i].id; if(vis[v]) query[id][2]=findr(v); } for(int i=0;i<G[u].size();i++) { int v=G[u][i].to; if(vis[v]) continue; tarjan(v,val+G[u][i].w); unite(u,v); } } int main() { int cas,n,op,u,v,w; scanf("%d",&cas); while(cas--) { scanf("%d %d",&n,&op); for(int i=1;i<=n;i++) { G[i].clear(); mp[i].clear(); vis[i]=0; par[i]=i; } for(int i=1;i<=n-1;i++) { scanf("%d %d %d",&u,&v,&w); G[u].push_back(Edge(v,w)); G[v].push_back(Edge(u,w)); } for(int i=1;i<=op;i++) { scanf("%d %d",&u,&v); query[i][0]=u; query[i][1]=v; mp[u].push_back((node){v,i}); mp[v].push_back((node){u,i}); } tarjan(1,0); for(int i=1;i<=op;i++) { int u=query[i][0]; int v=query[i][1]; int r=query[i][2]; printf("%d\n",dis[u]+dis[v]-2*dis[r]); } } return 0; }
分析:用的lca
1.因为有n-1条边,任意两点之间可达,那么就是一棵树;
2,假设当前是询问u和v两个点,他们的LCA是r,dis[]数组代表从根到点的距离,那么u和v两点之间的距离就是dis[u]+dis[v]-2*dis[r];所以只需要用Tarjan求一求询问的点对的LCA并且记录一下每个点到根(随便哪个点做根都可以)的距离就可以了