如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入格式:
第一行包含三个正整数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 Eage {
int to;
int next;
}edge[2*N];
int head[2 * N];
int deep[N];
int fa[N][20];
int cnt;
void init()
{
for (int i = 0; i < 2 * N; i++) //初始化链式向前星
{
head[i] = -1;
edge[i].next = -1;
}
cnt = 0;
}
void addEage(int u, int v)
{
edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++; //添加链式向前星
}
void dfs(int x,int father) //建立倍数跳跃模板
{
deep[x] = deep[father] + 1;
fa[x][0] = father;
for (int i = 1; (1 << i) <= deep[x]; i++) //倍增的模板,最远不能跳过根节点
{
fa[x][i] = fa[fa[x][i - 1]][i - 1];
}
for (int i = head[x]; i!=-1; i=edge[i].next)
{
if (edge[i].to != father)
dfs(edge[i].to, x);
}
}
int LCA(int x,int y)
{
if (deep[x] < deep[y]) { swap(x, y); }
for (int i = 19; i >= 0; i--)
{
if (deep[x] - (1 << i) >= deep[y])
x = fa[x][i];
}
if (x == y) return y;
for (int i = 19; i >= 0; i--)
{
if (fa[x][i] != fa[y][i]) //x和y相等会继续跳到最后一次相等为止
//if(x!=y) 一直相等
{
x = fa[x][i];
y = fa[y][i];
}
}
return x;
}
void solve()
{
init();
int n, m, root;
cin >> n >> m >> root;
for (int i = 1; i < n; i++)
{
int u, v;
cin >> u >> v;
addEage(u, v);
addEage(v, u);
}
dfs(root, 0);
while (m--)
{
int a, b;
cin >> a >> b;
cout<< LCA(a, b) << endl;
}
}
unsigned main()
{
ios::sync_with_stdio(false);
int num = 1;
while (num--)
{
solve();
}
}