参考:点击打开链接
觉得链接处的代码有的地方好像有问题,然后自己改了改拿了过来。。
问题描述:给定一个有根树,n个节点和n-1条边 以及q个查询 查询两个点的LCA 要求按输入顺序输出q个查询的答案。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <vector>
using namespace std;
const int maxn = 10000 + 7;
struct node {
int v, id;
};
int n, q, root;
int in[maxn]; /// 入度
int p[maxn], ran[maxn]; ///并查集
int ans[maxn], vis[maxn], res[maxn];
vector<int> G[maxn]; /// 树
vector<node> que[maxn]; /// 查询
int Find(int x) {
return p[x] == x ? x : p[x] = Find(p[x]);
}
void Union(int b, int a) {
int x = Find(a), y = Find(b);
if(x != y) {
if(ran[x] > ran[y]) p[y] = x;
else p[x] = y, ran[y] += ran[x] == ran[y];
}
}
void tarjan(int u) {
vis[u] = 1;
for(int i = 0; i < G[u].size(); ++i) {
tarjan(G[u][i]);
Union(u, G[u][i]);
ans[Find(u)] = u;
}
for(int i = 0; i < que[u].size(); ++i) {
if(vis[que[u][i].v]) {
res[que[u][i].id] = ans[Find(que[u][i].v)];
//printf("%d %d %d\n", u, que[u][i].v, ans[Find(que[u][i].v)]);
}
}
}
void init() {
memset(in, 0, sizeof(in));
memset(ran, 0, sizeof(ran));
for(int i = 0; i <= n; ++i) G[i].clear(), que[i].clear(), p[i] = i;
root = 0;
}
void input() {
scanf("%d%d", &n, &q);
int u, v;
init();
for(int i = 1; i < n; ++i) {
scanf("%d%d", &u, &v);
++in[v];
G[u].push_back(v);
}
for(int i = 0; i < q; ++i) {
scanf("%d%d", &u, &v);
que[u].push_back((node){v, i});
que[v].push_back((node){u, i});
}
for(int i = 1; i <= n; ++i) if(!in[i]) {
root = i;
break;
}
}
int main() {
input();
tarjan(root);
for(int i = 0; i < q; ++i)
printf("%d\n", res[i]);
return 0;
}
/**
7 5
1 3
3 5
5 7
3 4
1 2
2 6
4 7
4 5
6 7
3 2
4 6
**/