Hdu-2586-How far away ?

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HuangXinyue1017/article/details/82835355

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)
这不就是要求 L C A LCA 嘛……

你可以倍增(在线) 时间 O ( n l o g n ) O(nlogn) ,每次询问 O ( l o g n ) O(logn) ,空间 O ( n l o g n ) O(nlogn)
不会的看这里:https://blog.csdn.net/ouqingliang/article/details/74926229

亦可以DFS+RMQ(在线) 时间 O ( n l o g n ) O(nlogn) ,每次询问 O ( 1 ) O(1) ,空间 O ( n l o g n ) O(nlogn)
不会的看这里:https://blog.csdn.net/ouqingliang/article/details/76549194

也可以Tarjan(离线) 时间 O ( n + m ) O(n+m) ,每次询问 O ( 1 ) O(1) ,空间 ( n + m ) (n+m)
不会的看这里:https://blog.csdn.net/ouqingliang/article/details/52228429

求LCA的三种算法总结

鉴于我才知道离线求 L C A 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]]);
	}
}

猜你喜欢

转载自blog.csdn.net/HuangXinyue1017/article/details/82835355
今日推荐