题目链接
http://poj.org/problem?id=1330
本体题意就是给定一颗树,求a, b两点的最近公共父节点,直接用来学习模板,模板是网上大神的,我做了一点注释,容易理解。(我喜欢离线的处理)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#define rep(i, s, t) for(int i = s;i <= t;i++)
#define rap(i, s, t) for(int i = s;i >= t;i--)
using namespace std;
const int M = 10009;
vector<int>tree[M];
vector<int>query[M];
int n;
bool vis[M];
int in[M];
int f[M];
int root;
int ancestor[M];
int findd(int x)//递归找并查集标记
{
return x == f[x] ? f[x] : f[x] = findd(f[x]);
}
void uni(int x, int y)//合并并查集
{
x = findd(x);
y = findd(y);
if(x != y)
f[x] = y;
}
void init()//初始化
{
rep(i, 0, n){
vis[i] = false;
tree[i].clear();
query[i].clear();
in[i] = 0;
f[i] = i;
}
}
void input_tree()//建图,找树的根节点
{
rep(i, 0, n - 2){
int a, b;
scanf("%d%d", &a, &b);
tree[a].push_back(b);
in[b]++;//标记入度
}
rep(i, 1, n)//根节点的入度为0
if(in[i] == 0)
root = i;
}
void input_query()//离线读入询问
{
rep(i, 0, 0){
int a, b;
scanf("%d%d", &a, &b);
query[a].push_back(b);
query[b].push_back(a);
}
}
void tarjan(int x)
{
rep(i, 0, (int)tree[x].size() - 1){
int v = tree[x][i];
tarjan(v);//先处理子节点
uni(x, v);//合并子节点和父节点并查集
ancestor[findd(x)] = x;//改并查集的所有节点的父节点就是x
}
vis[x] =true;
rep(i, 0, (int)query[x].size() - 1)//由于更新父节点是从下向上更新的所以最先找到的公共父节点就是最近的父节点。
{
int v = query[x][i];
if(vis[v])
printf("%d\n", ancestor[findd(v)]);
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
init();
input_tree();
input_query();
tarjan(root);
}
return 0;
}