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-1個邊,每個邊有權值表示距離,問任意兩點的距離
思路
任意選擇一個作爲根,dis[ i ] 表示 i 結點到根的距離,用DFS走一遍數算出dis 。然後求x和y的距離,轉化爲求x和y的LCA問題,他們的最小公共祖先p,則x和y的距離就是 dis[ x ] + dis[ y ] - 2 * dis[ p ].
LCA用tarjan求,先把訪問的點x,y存在數組裏,DFS的時候記得查兩次。
另一種是LCA轉RMQ的做法,先用數組保存DFS序,保存結點的深度,最小公共祖先就是區間的最小值,即深度最小。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 40010;
struct Edge
{
int to,next,w;
}edge[maxn*2];
int head[maxn],tot=0;
void addEdge(int from,int to,int d)
{
edge[tot].to = to; edge[tot].w = d;
edge[tot].next = head[from];
head[from] = tot++;
}
int n,m,x,y,d,ans[210],vis[maxn],f[maxn],dis[maxn],query[210][2];
int Find(int x)
{
if(x==f[x]) return x;
else return f[x] = Find(f[x]);
}
void tarjan(int u)
{
vis[u] = 1;
for(int i=head[u];i!=-1;i=edge[i].next){
int v = edge[i].to;
if(vis[v]) continue;
tarjan(v);
f[v] = u;
}
vis[u] = 2;
for(int i=0;i<m;i++){
int x = query[i][0], y = query[i][1];
if(u==x&&vis[y]==2) ans[i] = Find(y);
if(u==y&&vis[x]==2) ans[i] = Find(x);
}
}
void dfs(int x,int fa)
{
for(int i=head[x];i!=-1;i=edge[i].next){
int u = edge[i].to;
if(u==fa) continue;
dis[u] = dis[x] + edge[i].w;
dfs(u,x);
}
}
int main()
{
int T; scanf("%d",&T);
while(T--)
{
tot = 0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
f[i] = i; head[i] = -1; vis[i] = 0; dis[i] = 0;
}
for(int i=1;i<n;i++){
scanf("%d%d%d",&x,&y,&d);
addEdge(x,y,d); addEdge(y,x,d);
}
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
query[i][0] = x; query[i][1] = y;
}
dfs(1,0);
tarjan(1);
for(int i=0;i<m;i++) printf("%d\n",dis[query[i][0]]+dis[query[i][1]]-2*dis[ans[i]]);
}
return 0;
}
LCA轉RMQ做法
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 40010;
int m,n,q,x,y,c,d,ST_Min[maxn*2][20];
struct Edge
{
int to,next,w;
}edge[maxn*2];
int head[maxn],tot=0;
void addEdge(int from,int to,int d)
{
edge[tot].to = to; edge[tot].w = d; edge[tot].next = head[from];
head[from] = tot++;
}
int cnt,num[maxn*2],deep[maxn*2],first[maxn],dis[maxn];
void dfs(int u,int fa,int dep)
{
num[++cnt] = u;
deep[cnt] = dep;
first[u] = cnt;
for(int i=head[u];i!=-1;i=edge[i].next){
int v = edge[i].to, w = edge[i].w;
if(v==fa) continue;
dis[v] = dis[u] + w;
dfs(v,u,dep+1);
num[++cnt] = u;
deep[cnt] = dep;
}
}
void ST_Init(int n)
{
for(int i=1;i<=n;i++) ST_Min[i][0] = i;
for(int j=1;(1<<j)<=n;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
int a = ST_Min[i][j-1], b = ST_Min[i+(1<<(j-1))][j-1];
if(deep[a]<=deep[b]) ST_Min[i][j] = a;
else ST_Min[i][j] = b;
}
}
}
int query_min(int l,int r)
{
int k = (int)(log(r-l+1.0)/log(2.0));
int a = ST_Min[l][k], b = ST_Min[r-(1<<k)+1][k];
if(deep[a]<=deep[b]) return a;
else return b;
}
int LCA(int u,int v)
{
int x = first[u], y = first[v];
if(x>y) swap(x,y);
return num[query_min(x,y)];
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
head[i] = -1; dis[i] = deep[i] = first[i] = 0;
}
tot = 0;
for(int i=1;i<n;i++){
scanf("%d%d%d",&x,&y,&d);
addEdge(x,y,d); addEdge(y,x,d);
}
cnt = 0;
dfs(1,-1,0);
ST_Init(2*n-1);
for(int i=1;i<=q;i++){
scanf("%d%d",&x,&y);
int lca = LCA(x,y);
// printf("x:%d y:%d lca:%d ::%d\n",dis[x],dis[y],dis[lca],lca);
printf("%d\n",dis[x]+dis[y]-2*dis[lca]);
}
}
return 0;
}