Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
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
Source
ECJTU 2009 Spring Contest
Solution
题目大意:给出一棵树,每两点之间有距离,求出每对点之间的距离
d
i
s
t
(
x
,
y
)
=
d
i
s
t
(
x
,
r
o
o
t
)
+
d
i
s
t
(
y
,
r
o
o
t
)
−
2
∗
d
i
s
t
(
l
c
a
(
x
,
y
)
,
r
o
o
t
)
dist(x,y)=dist(x,root)+dist(y,root)-2*dist(lca(x,y),root)
dist(x,y)=dist(x,root)+dist(y,root)−2∗dist(lca(x,y),root)
这不就是要求
L
C
A
LCA
LCA 嘛……
你可以倍增(在线) 时间
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),每次询问
O
(
l
o
g
n
)
O(logn)
O(logn) ,空间
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
不会的看这里:https://blog.csdn.net/ouqingliang/article/details/74926229
亦可以DFS+RMQ(在线) 时间
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn) ,每次询问
O
(
1
)
O(1)
O(1) ,空间
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
不会的看这里:https://blog.csdn.net/ouqingliang/article/details/76549194
也可以Tarjan(离线) 时间
O
(
n
+
m
)
O(n+m)
O(n+m) ,每次询问
O
(
1
)
O(1)
O(1),空间
(
n
+
m
)
(n+m)
(n+m)
不会的看这里:https://blog.csdn.net/ouqingliang/article/details/52228429
鉴于我才知道离线求 L C A LCA LCA 的方法,所以下面的是第三种方法
Code
#include<algorithm>
#include<cstring>
#include<cstdio>
#define fo(i,a,b) for(register int i=a;i<=b;++i)
#define fd(i,a,b) for(register int i=a;i>=b;--i)
using namespace std;
const int N=4e4+5,M=2e2+5;
int T,n,m,x,y,z,ee,qq;
int f[N],v[N],s[N],t[N],ed[N],qu[N],dis[N],lca[N];
struct edge
{
int to,next,len;
}e[2*N];
struct ques
{
int to,next,id;
}q[N];
void add_edge(int x,int y,int z)
{
e[++ee]=(edge){y,ed[x],z},ed[x]=ee;
}
void add_ques(int x,int y,int z)
{
q[++qq]=(ques){y,qu[x],z},qu[x]=qq;
}
int find(int x)
{
return f[x]=f[x]==x?x:find(f[x]);
}
void merge(int x,int y)
{
int fx=find(x),fy=find(y);
if(fx!=fy) f[fx]=fy;
}
void Tarjan(int x,int fa)
{
for(int i=ed[x];i;i=e[i].next)
if(e[i].to!=fa) dis[e[i].to]=dis[x]+e[i].len,Tarjan(e[i].to,x),merge(e[i].to,x);
v[x]=1;
for(int j=qu[x];j;j=q[j].next)
if(v[q[j].to]&&!lca[q[j].id]) lca[q[j].id]=find(q[j].to);
}
int main()
{
freopen("lca.in","r",stdin);
freopen("lca.out","w",stdout);
scanf("%d",&T);
while(T--)
{
memset(ed,0,sizeof(ed)),ee=0;
memset(qu,0,sizeof(qu)),qq=0;
memset(dis,0,sizeof(dis));
memset(lca,0,sizeof(lca));
scanf("%d%d",&n,&m);
fo(i,1,n-1)
{
scanf("%d%d%d",&x,&y,&z);
add_edge(x,y,z),add_edge(y,x,z);
}
fo(i,1,m)
{
scanf("%d%d",&x,&y);
add_ques(x,y,i),add_ques(y,x,i);
s[i]=x,t[i]=y;
}
fo(i,1,n) f[i]=i,v[i]=0;
Tarjan(1,0);
fo(i,1,m) printf("%d\n",dis[s[i]]+dis[t[i]]-2*dis[lca[i]]);
}
}