Tarjan 算法求 LCA / Tarjan 算法求强连通分量




洛谷P3379 【模板】最近公共祖先(LCA)

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include <set>
#include <stack>
#include <map>
#include<vector>
using namespace std;
const int maxn = 5e5 + 5;
struct query
{
	int x;
	int y;
	int lca;
}query[maxn];
int fa[maxn];
bool vis[maxn];
int deep[maxn];
vector<int> G[maxn];
vector<int> Q[maxn];

void init()
{
	for (int i = 0; i < maxn; i++)
	{
		fa[i] = i;
	}
}

int find(int x)
{
	if (fa[x] == x)
		return x;
	else
		return fa[x] = find(fa[x]);
}

void Union(int v, int u)
{
	int vfa = find(v), ufa = find(u);
	if (vfa == ufa)return;
	else fa[v] = u;
}

void tarjan(int u)
{
	vis[u] = true;
	for (auto qid : Q[u]) {
		if (query[qid].x == u) {
			if (vis[query[qid].y]) {
				query[qid].lca = find(query[qid].y);
			}
		}
		else
		{
			if (vis[query[qid].x]) {
				query[qid].lca = find(query[qid].x);
			}
		}
	}
	for (auto v : G[u]) {
		if (vis[v])
			continue;
		deep[v] = deep[u] + 1;
		tarjan(v);
		Union(v, u);
	}
}

int main()
{
	init();
	int n, m, s;
	scanf_s("%d%d%d", &n, &m, &s);
	int x, y;
	for (int i = 1; i < n; i++)
	{
		scanf_s("%d%d", &x, &y);
		G[x].push_back(y);
		G[y].push_back(x);
	}
	for (int i = 1; i <= m; i++)
	{
		scanf_s("%d%d", &query[i].x, &query[i].y);
		Q[query[i].x].push_back(i); // 对于节点 x 来说有一个编号为 i 的询问
		Q[query[i].y].push_back(i);
	}
	tarjan(s);
	for (int i = 1; i <= m; i++)
	{
		printf("%d\n", query[i].lca);
	}
	for (int i = 1; i <= n; i++)
	{
		printf("节点 %d 的深度是 %d\n", i, deep[i]);
	}
}

FOJ 1628 计算公共祖先的个数

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include <set>
#include <stack>
#include <map>
#include<vector>

using namespace std;
const int maxn = 5e5 + 5;
struct query
{
	int x;
	int y;
	int lca;
}query[maxn];
int fa[maxn];
bool vis[maxn];
int deep[maxn];
vector<int> G[maxn];
vector<int> Q[maxn];

void init()
{
	deep[1] = 1;
	for (int i = 0; i < maxn; i++)
	{
		fa[i] = i;
	}
}

int find(int x)
{
	if (fa[x] == x)
		return x;
	else
		return fa[x] = find(fa[x]);
}

void Union(int v, int u)
{
	int vfa = find(v), ufa = find(u);
	if (vfa == ufa)return;
	else fa[v] = u;
}

void tarjan(int u)
{
	for (int i = 0; i < Q[u].size(); i++) {
		if (query[Q[u][i]].x == u) {
			if (vis[query[Q[u][i]].y]) {
				query[Q[u][i]].lca = find(query[Q[u][i]].y);
			}
		}
		else
		{
			if (vis[query[Q[u][i]].x]) {
				query[Q[u][i]].lca = find(query[Q[u][i]].x);
			}
		}
	}
	vis[u] = true;
	for (int i = 0; i < G[u].size(); i++) {
		if (vis[G[u][i]])
			continue;
		deep[G[u][i]] = deep[u] + 1;
		tarjan(G[u][i]);
		Union(G[u][i], u);
	}
}

int main()
{
	init();
	int n, k, m;
	int x, y;
	scanf_s("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		scanf_s("%d", &k);
		for (int j = 1; j <= k; j++)
		{
			scanf_s("%d", &y);
			G[i].push_back(y);
			G[y].push_back(i);
		}
	}
	scanf_s("%d", &m);
	for (int i = 1; i <= m; i++) // 离线处理
	{
		scanf_s("%d%d", &query[i].x, &query[i].y);
		Q[query[i].x].push_back(i); // 对于节点 x 来说有一个编号为 i 的询问
		Q[query[i].y].push_back(i);
	}
	tarjan(1);
	/*for (int i = 1; i <= m; i++)
	{
		printf("%d\n", query[i].lca);
	}
	for (int i = 1; i <= n; i++)
	{
		printf("节点 %d 的深度是 %d\n", i, deep[i]);
	}*/
	for (int i = 1; i <= m; i++)
	{
		printf("%d\n", deep[query[i].lca]);
	}
}
posted @ 2019-10-20 12:17  畅畅1  阅读(338)  评论(0编辑  收藏  举报