问题描述
树是一种很常见的数据结构。现在蒜头君面临一个问题,在一个有 n 个节点的树上,节点编号分别是1…n。蒜头想知道一些节点之间的最近公共祖先是那些节点。
输入格式
第一行输入一个整数 n(2≤n≤10,000),表示树上有 n 个节点。
接下来的 n−1 行,每行输入俩个整数 a,b(1≤a,b≤n)代表节点 a,b 之间有一条 a 到 b 边,a 是 b 的父亲。
接下来输入一个整数 q,代表蒜头君的 q 次提问。(1≤q≤1,000)
接下来的 q 行,每行输入俩个整数 c,d(1≤c,d≤n)代表询问 c,d 俩个节点的最近公共祖先。
输出格式
对于每次询问,输出公共祖先的节点编号,占一行。
样例输入
5
1 2
2 3
1 4
2 5
2
3 4
3 5
样例输出
1
2
#include <iostream>
#include <cstring>
using namespace std;
const int MAX_N = 1000000;
const int MAX_M = 10000;
struct edge {
int v, next;
int len;
} E[MAX_M], qE[MAX_M];
int p[MAX_N], qp[MAX_N], eid, qeid;
bool is_root[MAX_N];
void init() {
memset(p, -1, sizeof(p));
memset(qp, -1, sizeof(qp));
memset(is_root, true, sizeof(is_root));
eid = 0;
qeid = 0;
}
void insert(int u, int v) {
E[eid].v = v;
E[eid].next = p[u];
p[u] = eid++;
}
void insertq(int u, int v) {
qE[qeid].v = v;
qE[qeid].next = qp[u];
qp[u] = qeid++;
}
int fa[MAX_N];
int get(int x) {
if (x == fa[x]) {
return x;
}
return fa[x] = get(fa[x]);
}
int ans[MAX_M];
bool vis[MAX_N];
void tarjan(int u){
for(int i=p[u];i!=-1;i=E[i].next){
tarjan(E[i].v);
fa[get(E[i].v)]=get(u);
}
vis[u]=true;
for(int i=qp[u];i!=-1;i=qE[i].next){
if(vis[qE[i].v]){
ans[i/2]=get(qE[i].v);
}
}
}
int main() {
int n;
cin>>n;
init();
for(int i=0;i<n-1;i++){
int u,v;
cin>>u>>v;
insert(u,v);
is_root[v]=false;
}
int q;
cin>>q;
for(int i=0;i<q;i++){
int u,v;
cin>>u>>v;
insertq(u,v);
insertq(v,u);
}
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=n;i++){
if(is_root[i]){
tarjan(i);
break;
}
}
for(int i=0;i<q;i++){
cout<<ans[i]<<endl;
}
return 0;
}