LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个节点u和v最近的公共祖先。(若u为v的祖先或者v为u的祖先,则LCA(u,v)就是作为祖先的那个节点)
现在有一棵以1为根的有根树,树上一共有n个节点。现在有m次查询,每次询问两个节点的LCA。
输入
第1行:一个正整数n,表示树上节点的个数。(1<=n<=1000)
第2行-第n行:每行两个正整数u,v,表示节点u到节点v有一条边。(1<=u,v<=n)
第n+1行:一个正整数m,表示查询的次数。(1<=m<=1000)
第n+2-第n+m+1行:每行两个正整数a,b,表示要查询的两个节点的编号。(1<=a,b<=n)
输出
对于每个询问,输出一个正整数表示答案,并换行。
输入样例
5
1 2
1 3
2 4
2 5
5
3 5
2 5
3 4
2 4
5 5
输出样例
1
2
1
2
5
板子来源
还不是很懂,待进一步学习
ps :auto 只有c++11可以使用
在dev中使用c++11:
点击菜单栏的“工具”-》“编译选项”进入如下界面,勾选“编译时加入以下指令”,填入"-std=c++11"
#include<bits/stdc++.h>
using namespace std;
const int N=2010; //序列个数为 2*n-1
vector<int>tr[N]; //邻接表存图
int vs[N]; //第i次访问节点的编号
int depth[N]; // 第i次访问节点的深度
int id[N]; //在vs数组中i节点第一次出现的下标
int vis[N]; //标记数组
int st[N][20]; //存最小值对应的下标
int n,m,x,y; //图的顶点,查询次数
int dfs_clock=1;
//计算并存储每个节点出的顺序与层数
void dfs(int u,int d) //当前点,它的父节点,点深度
{
id[u]=dfs_clock; //u第一次出现的下标是dfs_clock,从0开始
vs[dfs_clock]=u; //标记第dfs_clock访问节点是谁
depth[dfs_clock++]=d; //第dfs_clock访问节点的深度是d
for(auto x:tr[u])
{
if(vis[x]) //访问过的不再访问
continue;
vis[x]=1; //访问标记
dfs(x,d+1); //往下一层搜索,深度加1
vs[dfs_clock]=u; //回溯节点也要标记
depth[dfs_clock++]=d;
}
}
void RMQ(int nn)
{
for(int i=1;i<=nn;i++)
st[i][0]=i;
for(int j=1;(1<<j)<=nn;j++)
for(int i=1;i+(1<<j)-1<=nn;i++)
{
int a=st[i][j-1];
int b=st[i+(1<<(j-1))][j-1];
if(depth[a]<=depth[b])
st[i][j]=a;
else
st[i][j]=b;
}
}
int LCA(int u,int v)//返回u,v之间的最近公共祖先
{
int l=id[u];
int r=id[v];
if(l>r)
swap(l,r);
int k=log2(r-l+1);
int a=st[l][k];
int b=st[r-(1<<k)+1][k];
return depth[a]>depth[b]?vs[b]:vs[a];
}
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=0;i<n-1;i++)
{
cin>>x>>y;
tr[x].push_back(y);
tr[y].push_back(x);
}
vis[1]=1;//1标记以查询
dfs(1,0);//以1为根
RMQ(dfs_clock-1);
cin>>m;
while(m--)
{
cin>>x>>y;
cout<<LCA(x,y)<<endl;
}
return 0;
}