这道题的意思就是,给你一棵树,再从中取出任意两个节点,让你找他们的最近公共祖先,一个很裸地题,当倍增入门题不错。
由于数据比较水,暴力也能A
//暴力做法
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int fa[100005];
bool vis[100005];
int main()
{
int t,n,a,b;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i = 1; i <= n; i ++)
{
fa[i] = i;
}
memset(vis,0,sizeof(vis));
for(int i = 1; i <= n-1; i ++)
{
scanf("%d%d",&a,&b);
fa[b] = a;
}
scanf("%d%d",&a,&b);
while(fa[a] != a)
{
vis[a] = 1;
a = fa[a];
}
vis[a] = 1;
while(!vis[b])
{
b = fa[b];
}
cout <<b <<endl;
}
return 0;
}
//倍增求lca
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 20000;
int head[MAXN],nxt[MAXN<<1],tot = 0,fa[MAXN][17],in[MAXN],deep[MAXN];
bool vis[MAXN];
struct Edge
{
int from,to;
}e[MAXN<<1];
void build(int f,int t)
{
e[++tot].from = f;
e[tot].to = t;
nxt[tot] = head[f];
head[f] = tot;
}
void dfs(int x)
{
vis[x] = 1;
for(int i = 1; i <= 16; i ++)
{
if(deep[x] < (1<<i))
break;
fa[x][i] = fa[fa[x][i-1]][i-1];
}
for(int i = head[x]; i ; i = nxt[i])
{
if(vis[e[i].to])
continue;
fa[e[i].to][0] = x;
deep[e[i].to] = deep[x] + 1;
dfs(e[i].to);
}
}
int lca(int x,int y)
{
if(deep[x] < deep[y])
swap(x,y);
int t = deep[x] - deep[y];
for(int i = 0; i <= 16; i ++)
{
if(t & (1<<i))
x = fa[x][i];
}
for(int i = 16; i >=0; i --)
{
if(fa[x][i] != fa[y][i])
{
x = fa[x][i];
y = fa[y][i];
}
}
if(x == y)
return x;
return fa[x][0];
}
int main()
{
int t,n;
cin>>t;
while(t--)
{
memset(in,0,sizeof(in));
memset(deep,0,sizeof(deep));
memset(fa,0,sizeof(fa));
memset(vis,0,sizeof(vis));
memset(e,0,sizeof(e));
memset(nxt,0,sizeof(nxt));
scanf("%d",&n);
for(int i = 1; i <= n-1; i ++)
{
int aa,bb;
scanf("%d%d",&aa,&bb);
build(aa,bb);
fa[bb][0] = aa;
in[bb]++;
}
for(int i = 1; i <= n; i ++)
if(in[i] == 0)
dfs(i);//注意倍增是从根节点开始的
int x,y;
scanf("%d%d",&x,&y);
cout <<lca(x,y)<<endl;
}
return 0;
}