最近刚好学了树链剖分,来一道LCA的模板题练练手:P3379 最近公共祖先(LCA)
题意:给一棵多叉树,m次询问,求两个节点之间的LCA。
思路:树链剖分。
#include <bits/stdc++.h>
#include<cstring>
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define fori(a,b,c) for(int a=b;a<=c;a++)
#define ford(a,b,c) for(int a=c;a>=b;a--)
#define mem0(x) memset(x,0,sizeof(x))
#define mem1(x) memset(x,-1,sizeof(x))
using namespace std;
const int M=5e5+100;
vector<int> g[M];
int son[M],top[M],f[M],sz[M],dep[M],tot;
void dfs1(int s,int fa)
{
f[s]=fa;
dep[s]=dep[fa]+1;
sz[s]=1;
int ma=-1;
for(int i=0;i<g[s].size();i++)
{
int v=g[s][i];
if(v==fa)continue;
dfs1(v,s);
sz[s]+=sz[v];
if(sz[v]>ma)
{
ma=sz[v];
son[s]=v;
}
}
}
void dfs2(int s,int t)
{
top[s]=t;
if(!son[s])return;
dfs2(son[s],t);
for(int i=0;i<g[s].size();i++)
{
int v=g[s][i];
if(v==f[s]||v==son[s])continue;
dfs2(v,v);
}
}
int fd(int a,int b)
{
while(top[a]!=top[b])
{
if(dep[top[a]]<dep[top[b]])swap(a,b);
a=f[top[a]];
}
if(dep[a]<dep[b])swap(a,b);
return b;
}
int main()
{
int n,m,r,x,y;
scanf("%d%d%d",&n,&m,&r);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs1(r,r);
dfs2(r,r);
while(m--)
{
scanf("%d%d",&x,&y);
printf("%d\n",fd(x,y));
}
return 0;
}
来源:https://blog.csdn.net/qq_41365703/article/details/99684582