E - Nearest Common Ancestors
POJ - 1330#include<stdio.h>
#include<cstdlib>
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<stack>
#include<queue>
using namespace std;
typedef long long LL;
int par[10010];//父亲
int ra[10010], rb[10010];
queue<int>road;
void init(int n) {
for (int i = 0; i <= n; i++) {
par[i]=i;
}
}
int Find1(int x) { //不需要记录路径的查找
if (par[x] == x)return x;
else {
return Find1(par[x]);
}
}
int Find(int x) { //需要记录路径的查找
road.push(x);
if (par[x] == x)return x;
else {
return Find(par[x]);
}
}
void unite(int a, int b) {
if (Find1(a) == Find1(b))return;
par[b] = a; //不能按照并查集那样合并 find也不需要压缩路径
}
int main() {
int Case;
scanf_s("%d", &Case);
while (Case--) {
int n; scanf_s("%d", &n);
init(n);
for (int i = 0; i < n - 1; i++) {
int a, b;
scanf_s("%d%d", &a, &b);
unite(a, b);
}//建立并查集
int a, b;
scanf_s("%d%d", &a, &b);
int ia = -1, ib = -1;
while (!road.empty())road.pop();
Find(a);
while (!road.empty()) {
ra[++ia] = road.front();
road.pop();
}//路程放入数组
Find(b);
while (!road.empty()) {
rb[++ib] = road.front();
road.pop();
}//路程放入数组
while (ia >= 0 && ib >= 0) {
if (ra[ia] == rb[ib]) { ia--; ib--; }
else { printf("%d\n", ra[ia + 1]); break; }
}
if (ia < 0)printf("%d\n", rb[ib + 1]);
else if (ib < 0)printf("%d\n", ra[ia + 1]);
}
}
主要运用并查集,查询时候记录查询的路径,并比较两个路径的区别,即可找到最近的公共祖先。
注意:查询写了两个函数,一个是记录路径一个是不记录路径,若只写一个记录路径提交的时候会 Memory Limit Exceeded