HDU ACM 2586 How far away ?LCA->并查集+Tarjan(离线)算法

题意:一个村子有n个房子,他们用n-1条路连接起来,每两个房子之间的距离为w。有m次询问,每次询问房子a,b之间的距离是多少。

分析:近期公共祖先问题,建一棵树,求出每一点i到树根的距离d[i],每次询问a。b之间的距离=d[a]+d[b]-2*d[LCA(a,b)];LCA(a,b)是a,b的近期公共祖先。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<vector>
using namespace std;

#define N 50005
vector<int> map[N],w[N],query[N],num[N];
int p[N],d[N],res[N];
bool vis[N];
int n;

void Init()
{
	int i;
	for(i=1;i<=n;i++)
	{
		map[i].clear();
		w[i].clear();
		query[i].clear();
		num[i].clear();
		p[i]=i;
		d[i]=0;
		vis[i]=false;
	}
}

int Find(int x)
{
	if(p[x]!=x)
		p[x]=Find(p[x]);
	return p[x];
}

void Union(int x,int y)
{
	x=Find(x);
	y=Find(y);
	if(x!=y)
		p[y]=x;
}

void Tarjan(int cur,int v)
{
	int size,i,tmp;

	vis[cur]=true;
	d[cur]=v;
	size=map[cur].size();
	for(i=0;i<size;i++)
	{
		tmp=map[cur][i];
		if(vis[tmp]) continue;
		Tarjan(tmp,v+w[cur][i]);
		Union(cur,tmp);
	}
	size=query[cur].size();
	for(i=0;i<size;i++)
	{
		tmp=query[cur][i];
		if(!vis[tmp])continue;
		res[num[cur][i]]=d[cur]+d[tmp]-2*d[Find(tmp)];
	}
}

int main()
{
	int T,q,a,b,c,i;

	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&q);
		Init();
		for(i=1;i<n;i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			map[a].push_back(b);
			w[a].push_back(c);
			map[b].push_back(a);
			w[b].push_back(c);
		}
		for(i=0;i<q;i++)
		{
			scanf("%d%d",&a,&b);
			query[a].push_back(b);
			query[b].push_back(a);
			num[a].push_back(i);
			num[b].push_back(i);
		}
		Tarjan(1,0);
		for(i=0;i<q;i++)
			printf("%d\n",res[i]);
	}
	return 0;
}


posted @ 2015-12-22 11:39  lcchuguo  阅读(217)  评论(0编辑  收藏  举报