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 (1到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的题,第一次接触,网上查了查,根据原理(我参考的是这篇文章,只有方法,没有代码的http://www.cnblogs.com/ECJTUACM-873284962/p/6613379.html),按照自己的理解,写了代码,到现在了,应该要有提供思路,便有写代码的能力(也就是说现在的阶段应该提升思维,拓展思路最为重要),所以我所写的应该还有待优化的地方。这个代码是其中一种实现LCA的方式,有离线的思想
代码
#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
#include<vector>
#define maxn 6006
using namespace std;
struct node
{
int a,b;
}query[203];//离线保留询问
int ans[203];//询问对应的答案
struct edge
{
int to;
int dis;
};//保留边
bool vis[203];
int n,m;
int pre[40004];
bool vis2[40004];
int dis[40004];
vector<edge>tree[40004];
void getDis(int x,int father)//求出所有点到根节点的距离
{
int v;
for(int i=0;i<tree[x].size();i++)
{
v=tree[x][i].to;
if(v==father)
continue;
dis[v]=dis[x]+tree[x][i].dis;
getDis(v,x);
}
}
int findd(int x)//使用并查集,但是个人理解和并查集没有太大关系,只是借用了并差集的实现方式
{
return pre[x]==x?x:pre[x]=findd(pre[x]);
}
void LCA(int x,int father)//LCA啦
{
int v;
for(int i=0;i<tree[x].size();i++)
{
v=tree[x][i].to;
if(v==father)
continue;
LCA(v,x);
}
for(int i=0;i<m;i++)//对于200的询问量,线性扫一遍即可
{
if(vis[i])
continue;
if(x==query[i].a&&vis2[query[i].b])
{
ans[i]=dis[x]+dis[query[i].b]-2*dis[findd(query[i].b)];
vis[i]=true;
}
else
{
if(x==query[i].b&&vis2[query[i].a])
{
ans[i]=dis[x]+dis[query[i].a]-2*dis[findd(query[i].a)];
vis[i]=true;
}
}
}
int xx=findd(x);
pre[xx]=father;
vis2[x]=true;
}
int main()
{
dis[1]=0;//根到自己的距离当然为0
int t;
int a,b,w;
scanf("%d",&t);
while(t--)
{
memset(vis,false,sizeof(vis));
memset(vis2,false,sizeof(vis2));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
tree[i].clear();
for(int i=1;i<=n;i++)
pre[i]=i;//都是初始化,其实我很少写init()函数,因为不知道为什么总是忘了写到main里。。。
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&a,&b,&w);
edge e;
e.dis=w;
e.to=a;
tree[b].push_back(e);//存边
e.to=b;
tree[a].push_back(e);
}
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
query[i].a=a;
query[i].b=b;//村存查询
}
getDis(1,-1);
//cout<<"yes";
LCA(1,-1);
for(int i=0;i<m;i++)
printf("%d\n",ans[i]);
}
return 0;
}
入门LCA的一道好题,难度不大