图论--LCA
离线Tarjan
算法思想
离线处理,先记录需要找的点
链式前向星模板
#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define cin(a) scanf("%d",&a)
#define pii pair<int,int>
#define ll long long
#define gcd __gcd
const int inf = 0x3f3f3f3f;
const int maxn = 1000100;
const int M = 1e9+7;
int n,m,s,cnt;
int head[maxn],to[maxn],Next[maxn]; //链式前向星
vector<pii> q[maxn]; //询问
int pre[maxn]; //先驱
bool vis[maxn]; //是否访问过
int ans[maxn]; //记录第i个询问的答案
void add(int u,int v)
{
to[cnt] = v;Next[cnt] = head[u]; head[u] = cnt;
cnt++;
}
int find(int x)
{
return x == pre[x] ? x : pre[x] = find(pre[x]);
}
void dfs(int u,int from)
{
for(int i = head[u]; i != -1; i = Next[i])
{
int v = to[i];
if(v != from)
{
dfs(v,u);
pre[v] = u;
}
}
for(auto j : q[u])
{
if(vis[j.first])
{
ans[j.second] = find(j.first);
}
}
vis[u] = 1;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("data.in", "r", stdin);
//freopen("data.out", "w", stdout);
#endif
scanf("%d%d%d",&n,&m,&s);
for(int i = 1; i <= n; i++) head[i] = -1,pre[i] = i;
for(int i = 1,u,v; i < n; i++)
{
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
for(int i = 1,u,v; i <= m; i++)
{
scanf("%d%d",&u,&v);
q[u].push_back(make_pair(v,i));
q[v].push_back(make_pair(u,i));
}
dfs(s,0);
for(int i = 1; i <= n; i++) printf("%d\n",ans[i]);
return 0;
}
倍增LCA
预处理过程:O(nlogn)
先用dfs或者bfs求出每个点的deep,然后更新每个点的fa数组
查询过程:O(logn)
1.假设x的深度更小(在y的上面)
2.y开始向上跳,跳到和x同深度
3.x,y一起向上跳
int d[maxn]; //深度
int fa[maxn][20]; //节点i的2^i级祖先
void dfs(int u,int pre)
{
d[u] = d[pre]+1;
fa[u][0] = pre;
for(int i = 1; (1<<i) <= d[u]; i++)
{
fa[u][i] = fa[fa[u][i-1]][i-1];
}
for(int i = head[u]; i ; i = Next[i])
{
int v = to[i];
if(v != pre)
{
dfs(v,u);
}
}
}
//t = log(n)/log(2)+1; 可能的最大深度
int lca(int x,int y)
{
if(d[x] > d[y]) swap(x,y); //让x的深度更小
for(int i = t; i >= 0; i--) //首先y要跳到和x深度相同
{
if(d[fa[y][i]] >= d[x]) y = fa[y][i]; //如果y^i还是在x下面,跳到y^i
}
//此时,x和y的深度一定相等
if(x == y) return x; //如果就是x,return
for(int i = t; i >= 0; i--) //从打的开始
{
if(fa[x][i] != fa[y][i]) //如果x的第i层和y的第i层不相同,如果相同说明跳过头了
{
x = fa[x][i];y=fa[y][i];
}
}
return fa[x][0]; //此时的x的父节点一定是lca
}
参考博客
https://www.cnblogs.com/JVxie/p/4854719.html
https://www.cnblogs.com/hulean/p/11144059.html
https://blog.csdn.net/zhaoxinxin1234/article/details/89764483