How far away ?
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
思路:
LCA就是寻找最近公共祖先,这有什么用呢?
假设B和C的最近公共祖先是A,那么对于整个树的根节点D,
都有:|BD|+|CD|-|AD|*2=|BC|
Code:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int N=41111;
typedef pair<int ,int > pii;
ll bit[30];//存2的次方用的
int f[N][30];//存第2^j的祖先
int depth[N];//存每一个节点离根结点的深度
vector<pii > vt[N];//存图用的
int in[N];//保存每个点的入度用的
int dis[N];//保存每个节点到根节点的距离
int vis[N];//标记数组
void init()
{//构建2的次方数组,初始化的时候做的
bit[0]=1;
for(int i=1;i<=29;i++)bit[i]=bit[i-1]*2;
}
//LCA模板
void dfs(int u,int par)
{
depth[u]=depth[par]+1;
f[u][0]=par;
for(int i=1;i<=29;i++) f[u][i]=f[f[u][i-1]][i-1];
for(int i=0;i<(int)vt[u].size();i++){
int v=vt[u][i].first;
if(v==par) continue;
dfs(v,u);
}
}
int lca(int a,int b)
{
if(depth[a]<depth[b]) swap(a,b);
int dif=depth[a]-depth[b];
for(int i=29;i>=0;i--){
if(dif>=bit[i]){
a=f[a][i];
dif-=bit[i];
}
}
if(a==b) return a;
for(int i=29;i>=0;i--){
if(depth[a]>=bit[i]&&f[a][i]!=f[b][i]){
a=f[a][i];b=f[b][i];
}
}
return f[a][0];
}
void bfs(int x)
{//bfs用来求树根到每一个点的距离,也是模板
memset(vis,0,sizeof vis);
queue<int >q;
q.push(x);
dis[x]=0;
vis[x]=1;
while(!q.empty()){
int t=q.front();
q.pop();
for(int i=0;i<vt[t].size();i++){
if(!vis[vt[t][i].first]){
vis[vt[t][i].first]=1;
dis[vt[t][i].first]=dis[t]+vt[t][i].second;
q.push(vt[t][i].first);
}
}
}
}
int main()
{
init();
int t;
scanf("%d",&t);
int n,m;
int a,b,c;
while(t--)
{
memset(in,0,sizeof in);//初始化
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
vt[i].clear();//初始化
for(int i=0;i<n-1;i++){
scanf("%d%d%d",&a,&b,&c);
vt[a].push_back(make_pair(b,c));
vt[b].push_back(make_pair(a,c));
in[b]++;//入度+1
}
int ans;
for(int i=1;i<=n;i++)
if(!in[i]){
ans=i;//找根节点
break;
}
memset(dis,0,sizeof dis);//初始化
bfs(ans);//找距离
dfs(ans,0);//LCA预处理
for(int j=0;j<m;j++){
scanf("%d%d",&a,&b);
c=lca(a,b);//找到最近祖先
printf("%d\n",dis[a]+dis[b]-2*dis[c]);
}
}
return 0;
}