LCA:一个树,给你两个点,问这两个点的最近公共祖先
方法一:dfs,直接先将一个点的祖先求出来,再看另外一个点祖先什么时候与之相遇(用一个标记数组),这样的话,每个询问都是n的时间复杂度
时间复杂度为o(q*n)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 10005;
int father[maxn],vis[maxn];
int main()
{
int n,i,j,k,sum,a,b,t,x,y;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(vis,0,sizeof(vis));
memset(father,-1,sizeof(father));
for(i=1;i<n;i++)
{
scanf("%d %d",&x,&y);
father[y]=x;
}
scanf("%d %d",&a,&b);
while(b!=-1)
{
vis[b]=1;
b=father[b];
}
while(!vis[a])
a=father[a];
printf("%d\n",a);
}
return 0;
}
法二:tarjian离线法(离线处理,就是将所有m个询问都存起来,然后一起输出)时间复杂度为n+q
int getf(int k)
{
if(k==f[k]) return k;
else return f[k]=getf(f[k]);
}
void uin(int a,int b)
{
int x=getf(a),y=getf(b);
if(x!=y) f[y]=x;
}
//这里的f和anc数组是不一样的。//最主要的竟然是anc数组。。//因为f中存的是最终的爸爸是谁,anc存的是当前i的上一个爸爸是谁
void Tarjan(int u)
{
anc[u]=u;
for(int i=head[u];i>-1;i=edge[i].pre)
{
node e=edge[i];
if(!vis[e.to])
{
vis[e.to]=1;
Tarjan(e.to);
uin(u,e.to);
}
}
col[u]=1;
for(int i=hq[u];i>-1;i=q[i].pre)
{
node e=q[i];
if(!col[e.to]) continue;
ans[e.id]=d[u]+d[e.to]-2*d[f[getf(e.to)]];//不能直接f[e.to],因为这里确保是最上面的祖先,因为uin的时候f[y]=x,但是以y为爸爸的孩子们的爸爸还没有改到x~
}
}
法三:ST在线求LCA
又偷队友代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
const int maxn = 10010;
struct node
{
int to,pre;
}e[maxn*2];
int vis[maxn];
int dep[maxn];
int head[maxn];
int dp[maxn][30];
int h=0;
void init()
{
h=0;
memset(e,0,sizeof(e));
memset(vis,0,sizeof(vis));
memset(dep,0,sizeof(dep));
memset(head,-1,sizeof(head));
}
void add(int from,int to)
{
e[h].to=to,e[h].pre=head[from];head[from]=h;h++;
}
void dfs(int u,int fa,int d)
{
dep[u]=d;
for(int i=head[u];i>-1;i=e[i].pre)
{
node t=e[i];
if(t.to==fa) continue;
dp[t.to][0]=u;
dfs(t.to,u,d+1);
}
}
void rmp(int n)
{
for(int i=1;i<20;i++)
{
for(int j=1;j<=n;j++)
{
if((1<<i)>dep[j])continue;
int k=dp[j][i-1];dp[j][i]=dp[k][i-1];
}
}
}
int query(int x,int y)
{
if(dep[x]>dep[y]) swap(x,y);
for(int j=20;j>=0&&dep[x]!=dep[y];j--)
{
if(dep[y]-(1<<j)<dep[x]) continue;
y=dp[y][j];
}
if(x==y) return x;
for(int j=20;j>=0;j--)
{
if(dep[x]-(1<<j)<0||dp[x][j]==dp[y][j]) continue;
x=dp[x][j],y=dp[y][j];
}
return dp[x][0];
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
init();
int n;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d %d",&x,&y);
add(x,y),add(y,x);vis[y]=1;
}
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
dfs(i,i,0);
break;
}
}
rmp(n);
int x,y;
scanf("%d %d",&x,&y);
printf("%d\n",query(x,y));
}
return 0;
}