如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入格式:
第一行包含三个正整数N , M , S N,M,SN,M,S,分别表示树的结点个数、询问的个数和树根结点的序号。接下来N − 1 N-1N−1行每行包含两个正整数x , y x,yx,y,表示x xx结点和y yy结点之间有一条直接连接的边(数据保证可以构成树)。接下来M MM行每行包含两个正整数a , b a,ba,b,表示询问a aa结点和b bb结点的最近公共祖先。
输出格式:
输出包含M MM行,每行包含一个正整数,依次为每一个询问的结果。
#include <iostream>
using namespace std;
const int N = 10010;
struct Edge
{
int next;
int to;
}edge[2 * N];
struct Tar
{
int next;
int to;
int num;
}tar[2 * N];
int head[2 * N]; //以i节点的第一条边
int tarHead[2 * N];
int cnt,cnt_tar;
int deep[N];
int fa[N][20]; //公共祖先模板
int s[N*2]; //并查集
bool vis[N*2]; //回溯标记
int ans[N * 2]; //记录公共祖先
void init()
{
for (int i = 0; i < 2 * N; i++) //初始化
{
edge[i].next = -1; head[i] = -1;
tar[i].next = -1; tarHead[i] = -1;
}
cnt = 0; cnt_tar = 0;
}
void addEdge(int u, int v) //初始化链式向前星
{
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void addTar(int u, int v,int t) //初始化要求的公共祖先节点关系
{
tar[cnt_tar].to = v;
tar[cnt_tar].next = tarHead[u];
tar[cnt_tar].num = t;
tarHead[u] = cnt_tar++;
}
int find_set(int x) // 找到公共祖先
{
return x == s[x] ? x : find_set(s[x]);
}
void Tarjan(int x) //后序遍历dfs树,找到当前树的公共祖先关系
{
vis[x] = true;
for (int i = head[x]; ~i; i = edge[i].next)
{
int y = edge[i].to;
if (!vis[y])
{
Tarjan(y);
s[y] = x;
}
}
for (int i = tarHead[x]; ~i; i = tar[i].next)
{
int z = tar[i].to;
if (vis[z])
{
ans[tar[i].num] = find_set(z);
}
}
}
void solve()
{
init();
int n, m, root;
cin >> n >> m >>root;
memset(vis, 0, sizeof(vis));
for (int i = 1; i < n; i++)
{
int u, v;
s[i] = i;
cin >> u >> v;
addEdge(u, v);
addEdge(v, u);
}
s[n] = n;
for (int i = 1; i <=m; i++)
{
int u,v;
cin >> u >> v;
addTar(u,v,i);
addTar(v, u, i);
}
Tarjan(root);
for (int i = 1; i <= m; i++)
cout<< ans[i] << endl;
}
unsigned main()
{
ios::sync_with_stdio(false);
int num = 1;
while(num--)
solve();
}