POJ 1330

LCA 问题,因为查询操作很少,这次使用离线的Tarjan算法

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <utility>
#include <stack>
#include <vector>
#include <cstring>
#define WHITE -1
#define BLACK 0 
using namespace std;

const int maxn= 1e4+3;

vector<vector<int> > fa;
int cl[maxn], mk[maxn];
int qa, qb;
int dad[maxn];
int nca;

void Init(int n)
{
	fa.clear();
	fa.resize(n+3);
	memset(cl, WHITE, sizeof(cl));
	memset(mk, -1, sizeof(mk));
}
int Find(int a)
{
	if (a== dad[a]){
		return dad[a];
	}

	return dad[a]= Find(dad[a]);
}
void Union(int a, int b)
{
	a= Find(a);
	b= Find(b);
	if (a== b){
		return;
	}
	if (mk[b]< mk[a]){
		dad[a]= dad[b];
	}
	else{
		dad[b]= dad[a];
	}
}
void dfs(int u, int d)
{
	int sn;
	mk[u]= d;
	dad[u]= u;
	for (int i= 0; i< int(fa[u].size()); ++i){
		sn= fa[u][i];
		dfs(sn, d+1);
		dad[sn]= u;	
	}
	if (u==qa && BLACK== cl[qb]){
		nca= Find(qb);
		return;
	}
	if (u== qb && BLACK== cl[qa]){
		nca= Find(qa);
		return;
	}
	cl[u]= BLACK;
}
int main(void)
{
	int T, n;	
	int nd, snd, rt;
	scanf("%d", &T);

	while (T--){
		scanf("%d", &n);
		Init(n);
		for (int i= 0; i< n-1; ++i){
			scanf("%d %d", &nd, &snd);
			fa[nd].push_back(snd);
			mk[snd]= 0;
		}	
		scanf("%d %d", &qa, &qb);
		for (int i= 1; i<= n; ++i){
			if (mk[i]){
				rt= i;
				break;
			}
		}

		dfs(rt, 1);
		printf("%d\n", nca);

	}
	return 0;
}

使用倍增算法

#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <cmath>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <deque>
using namespace std;

const int INF= 1<<30;
const int maxn= 1e4+5;
const int maxd= 21;

struct Edge
{
	int to, next;
	Edge(int t= 0, int n= 0) : to(t), next(n) {}
}pool[maxn];
int n;
int tot;
int head[maxn], dep[maxn];
int pre[maxn][maxd];
bool nofa[maxn];

inline void AddEdge(int u, int v)
{
	pool[tot].next= head[u];
	pool[tot].to= v;
	head[u]= tot;
	++tot;
}
void bfs(int rt)
{
	queue<int> Q;
	memset(dep, 0x3f, sizeof(dep));
	dep[rt]= 0;
	pre[rt][0]= rt;
	Q.push(rt);
	int cur, d;

	while (!Q.empty()){
		cur= Q.front();
		Q.pop();
		for (int i= 1; i < maxd; ++i){
			pre[cur][i]= pre[pre[cur][i-1]][i-1];
		}

		d= dep[cur]+1;

		for (int i= head[cur]; ~i; i= pool[i].next){
			int to= pool[i].to;
			if (pre[cur][0] == to){
				continue;
			}
			dep[to]= d;
			pre[to][0]= cur;
			Q.push(to);
		}
	}
}
int LCA(int u, int v)
{
	if (dep[v] > dep[u]){
		swap(u, v);
	}
	for (int d= dep[u]-dep[v], i= 0; d; d>>=1, ++i){
		if (d & 1){
			u= pre[u][i];
		}
	}
	if (u == v){
		return u;
	}

	for (int i= maxd-1; i >= 0; --i){
		if (pre[u][i] == pre[v][i]){
			continue;
		}
		u= pre[u][i];
		v= pre[v][i];
	}

	return pre[u][0];
}

int main(int argc, char const *argv[])
{
	int kase;
	scanf("%d", &kase);

	while (kase--){
		scanf("%d", &n);
		memset(nofa, 0, sizeof(nofa));
		memset(head, -1, sizeof(head));
		tot= 0;
		int u, v;
		for (int i= 1; i < n; ++i){
			scanf("%d%d", &u, &v);
			AddEdge(u, v);
			nofa[v]= 1;
		}
		
		int rt= -1;
		for (int i= 1; i <= n; ++i){
			if (!nofa[i]){
				rt= i;
				break;
			}
		}

		bfs(rt);
		scanf("%d%d", &u, &v);
		printf("%d\n", LCA(u, v));
	}
	return 0;
}
posted @ 2020-03-29 10:39  IdiotNe  阅读(73)  评论(0编辑  收藏  举报