POJ 1470 Closest Common Ancestors LCA题解

本题也是找LCA的题目,不过要求多次查询,一般的暴力查询就必然超时了,故此必须使用更高级的方法,这里使用Tarjan算法。

本题处理Tarjan算法,似乎输入处理也挺麻烦的。

注意: 因为查询的数据会极大,故此使用一个数组记录所有查询数据就会超时的。我就载在这里了。查了好久才想到这点。因为我使用了一个vector容器记录了查询数据,故此每次都循环这组这么大的数据,就超时了。----解决办法:使用一个vector<int> quest来记录查询数组,这样每次都只需要循环某节点的邻接查询点就可以了,数据量是很小的。

有些说法没道理的:比如:结尾是否有空格?没有!

我使用了按权值查询并查集的优化,实验证明:没有优化效果。

使用map容器记录结果,好像没有加速,不过这样的代码更加成熟。

其他就是Tarjan算法了,网上也不少解说的了,结合代码学习,这个算法也不难。

#include <stdio.h>
#include <vector>
#include <string.h>
#include <algorithm>
#include <map>
using namespace std;

struct Node
{
	bool notRoot;
	bool vis;
	vector<int> child;
};

const int MAX_N = 901;
int N, u, v, n;
Node Tree[MAX_N];
//vector<int> quest;//这样记录就会超时,应该是因为需要查询的数据极其大,所以引发超时
vector<int> quest[MAX_N];
map<int, int> ans;
int par[MAX_N];
int rank[MAX_N];
int ancestor[MAX_N];

void init(int n)
{
	for (int i = 1; i <= n; i++)
	{
		Tree[i].child.clear();
		Tree[i].notRoot = false;
		Tree[i].vis = false;
		quest[i].clear();
	}
}

int find(int x)
{
	if (!par[x]) return x;
	return par[x] = find(par[x]);
}

void unionTwo(int x, int y)
{
	x = find(x);
	y = find(y);
	if (x == y) return;
	if (rank[x] < rank[y]) par[x] = y;
	else
	{
		par[y] = x;
		rank[x]++;
	}
}

void LCATarjan(int r)
{
	//ancestor[r] = r;
	for (int i = 0; i < (int)Tree[r].child.size(); i++)
	{
		int v = Tree[r].child[i];
		//if (Tree[v].vis) continue;
		LCATarjan(v);
		unionTwo(r, v);
		ancestor[find(r)] = r;
	}
	Tree[r].vis = true;
	for (int i = 0; i < (int)quest[r].size(); i++)
	{
		int v = quest[r][i];
		if (Tree[v].vis) ans[ancestor[find(v)]]++;
	}
}

int main()
{
	while (scanf("%d", &N) != EOF)
	{
		init(N);
		memset(par, 0, sizeof(int) * (N+1));
		memset(ancestor, 0, sizeof(int) * (N+1));
		memset(rank, 0, sizeof(int) * (N+1));

		for (int i = 0; i < N; i++)
		{
			scanf("%d", &u);
			while (getchar() != '(') ;
			scanf("%d", &n);
			while (getchar() != ')') ;
			for (int j = 0; j < n; j++)
			{
				scanf("%d", &v);
				Tree[u].child.push_back(v);
				Tree[v].notRoot = true;
			}
		}		

		scanf("%d", &n);
		for (int i = 0; i < n; i++)
		{
			char a = getchar();
			while (a != '(') a = getchar();
			u = 0;
			a = getchar();
			while (a != ' ')
			{
				u = (u <<3) + (u<<1) + (a - '0');
				a = getchar();
			}
			v = 0;
			a = getchar();
			while (a != ')')
			{
				v = (v<<3) + (v<<1) + (a - '0');
				a = getchar();
			}
			quest[u].push_back(v);
			quest[v].push_back(u);
		}

		int root = 0;
		for (int i = 1; i <= N; i++)
		{
			if (!Tree[i].notRoot)
			{
				root = i;
				break;
			}
		}
		ans.clear();
		LCATarjan(root);

		map<int, int>::iterator it;
		for (it = ans.begin(); it != ans.end(); it++)
		{
			printf("%d:%d\n", it->first, it->second);
		}
	}
	return 0;
}

POJ 1470 Closest Common Ancestors LCA题解

时间: 2024-10-12 20:46:50

POJ 1470 Closest Common Ancestors LCA题解的相关文章

poj 1470 Closest Common Ancestors LCA

题目链接:http://poj.org/problem?id=1470 Write a program that takes as input a rooted tree and a list of pairs of vertices. For each pair (u,v) the program determines the closest common ancestor of u and v in the tree. The closest common ancestor of two n

POJ 1470 Closest Common Ancestors(LCA&amp;RMQ)

题意比较费劲:输入看起来很麻烦.处理括号冒号的时候是用%1s就可以.还有就是注意它有根节点...Q次查询,我是用在线st做的. /************************************************************************* > File Name: 3.cpp > Author: Howe_Young > Mail: [email protected] > Created Time: 2015年10月08日 星期四 19时03分

POJ 1470 Closest Common Ancestors【最近公共祖先LCA】

题目链接:http://poj.org/problem?id=1470 题目大意:给出一棵树,再给出若干组数(a,b),输出节点a和节点b的最近公共祖先(LCA) 就是很裸的LCA,但是我用的是<挑战程序设计竞赛>上的"基于二分搜索的算法求LCA",我看网上用的都是tarjan算法.但是我的代码不知道为什么提交上去 wrong answer,自己想的很多测试数据也都和题解结果一样,不知道错在哪里,所以把代码保存一下,留待以后解决...... 如果读者有什么建议,希望提出来,

poj 1470 Closest Common Ancestors 【Tarjan 离线 LCA】

题目:poj 1470 Closest Common Ancestors 题意:给出一个树,一些询问.求LCA的个数. 分析:很简单的模板题目,但是模板不够优秀,一直wa...RE,各种错误一下午,终于发现自己模板的漏洞了. AC代码: #include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; #define N 1010 #

POJ 1330 Nearest Common Ancestors LCA题解

本题是一个多叉树,然后求两点的最近公共单亲节点. 就是典型的LCA问题.这是一个很多解法的,而且被研究的很透彻的问题. 原始的解法:从根节点往下搜索,若果搜索到两个节点分别在一个节点的两边,那么这个点就是最近公共单亲节点了. Trajan离线算法:首次找到两个节点的时候,如果记录了他们的最低单亲节点,那么答案就是这个最低的单亲节点了. 问题是如何有效记录这个最低单亲节点,并有效根据遍历的情况更新,这就是利用Union Find(并查集)记录已经找到的节点,并及时更新最新访问的节点的当前最低单亲节

POJ 1470 Closest Common Ancestors 【LCA】

任意门:http://poj.org/problem?id=1470 Closest Common Ancestors Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 22519   Accepted: 7137 Description Write a program that takes as input a rooted tree and a list of pairs of vertices. For each pa

POJ 1470 Closest Common Ancestors

传送门 Closest Common Ancestors Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 17306   Accepted: 5549 Description Write a program that takes as input a rooted tree and a list of pairs of vertices. For each pair (u,v) the program determines

POJ 1470 Closest Common Ancestors 采用树结构的非线性表编程

A - Closest Common Ancestors(8.4.9) Time Limit:2000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Description Write a program that takes as input a rooted tree and a list of pairs of vertices. For each pair (u,v) the prog

POJ 1470 Closest Common Ancestors (在线LCA转RMQ)

题目地址:POJ 1470 LCA模板题..输入有点坑,还有输入的第一个结点不一定是根节点. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include