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;
}
时间: 2024-10-28 20:31:00

HDU ACM 2586 How far away ?LCA-&gt;并查集+Tarjan(离线)算法的相关文章

HDU ACM 2586 How far away ?LCA-&gt;并查集+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

笔记:LCA最近公共祖先 Tarjan(离线)算法

LCA最近公共祖先 Tarjan他贱(离线)算法的基本思路及其算法实现 本文是网络资料整理或部分转载或部分原创,参考文章如下: https://www.cnblogs.com/JVxie/p/4854719.html http://blog.csdn.net/ywcpig/article/details/52336496 https://baike.baidu.com/item/最近公共祖先/8918834?fr=aladdin 最近公共祖先简称LCA(Lowest Common Ancesto

HDU 5458 Stability(双连通分量+LCA+并查集+树状数组)(2015 ACM/ICPC Asia Regional Shenyang Online)

题目大意:给一个N个点M条边的无向图,有Q个询问:1.删掉a.b之间所存在的边:2.询问有多少条边,单独删掉之后a与b不再连通. 思路:脑洞大开. 对于询问,首先想到的就是a与b之间有多少桥(割边),然后想到双连通分量,然而删边是个坑爹的问题,于是我们离线倒着来,把删边变成加边. 双连通分量这种东西呢,其实缩点连起来之后,就是一棵树辣. 然后询问两个点的时候,设根到点x的距离为dep[x],a.b的最近公共祖先为lca(a, b),那么询问query(a, b) = dep[a] + dep[b

HDU ACM 1512 Monkey King-&gt;左偏树+并查集

题意:一开始有N只猴子,,每只都有一个力量值.,并且互不认识,后来 它们之间发生了M次斗争. 每次两次两只猴子a,b斗争是, a和 b都会从他们自己的朋友圈里拉出一个最强的朋友, 之后最强的这两只猴子打, 打完后两只猴子的力量值分别减半..并且 两只猴子的朋友圈的所有人都互相认识(也就是以后不会再打了).问题是对于每次斗争, 若a,b是朋友, 那么输出-1, 否则输出斗争后它们的朋友圈里最强猴子的力量值. 分析:要表示集合的合并查找操作就是并查集最好了:要维护每次的最大值,就可以使用大顶堆,但还

HDU ACM : 1875 畅通工程再续-&gt;最小生成树(并查集)

解析:最小生成树:Kruskal 算法:并查集实现. 1.首先找出符合要求的边: 2.对找出的边排序: 3.并查集找出n-1条边,无法修通n-1条路则无法实现要求. #include<iostream> #include<cmath> #include<algorithm> using namespace std; struct Point { int x,y; } point[102]; struct Edge { int a,b; double v; bool op

LCA最近公共祖先 Tarjan离线算法

学习博客:  http://noalgo.info/476.html 讲的很清楚! 对于一颗树,dfs遍历时,先向下遍历,并且用并查集维护当前节点和父节点的集合.这样如果关于当前节点(A)的关联节点(B)(及要求的最近祖先的另一个点)之前被访问过,那么 B可定已经属于一个集合,先前对于访问过的点,已经维护了那个点所在集合的根,所以找到B节点所在集合的根,那么这个点就是最近的根,因为对于dfs访问的顺序.

LCA(最近公共祖先)--tarjan离线算法 hdu 2586

HDU 2586 How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11320    Accepted Submission(s): 4119 Problem Description There are n houses in the village and some bidirectional roads c

HDU 2586 How Far Away?(Tarjan离线算法求lca)

题意:给定一棵树n个节点m个询问,每次询问两个节点之间的距离. 思路:Tarjan离线算法求lca. 这题一开始交了n发一直爆栈.......百度了一下大概说的是这样hdu用的是windows服务器所以栈大小极其坑爹,稍微深一点的递归就会爆栈(正式比赛一般不会爆) 解决方法就是加一句#pragma comment(linker, "/STACK:1024000000,1024000000") 用c++交就好.....当然这只是针对比较坑爹oj来说的取巧的方法 #include<c

hdu 1829 A Bug&#39;s Life (基础并查集)

题目: 链接:点击打开链接 题意: 给定虫子的交配关系,确定实验是否支持教授的假设即没有同性恋或者不符合假设. 思路: 是一道基础的并查集题目.存在两个集合异性和同性,给出多组关系,看这两个集合有木有联系,即是否有同性恋. 定义一个数组sex[],sex[i]表示与编号i的性别相反的虫子编号.然后将和i虫子有联系的合并为同一个集合(认为是同性的).如果findset(u) == findset(v),出现了反常行为. 代码: #include <iostream> #include <c