lca是图论里面较重要的东西
因为很多问题都需要用到 lca 比如路径问题
总之很有用
//1.倍增算法
#include<iostream>
using namespace std;
#include<vector>
const int maxn = 1e6+5;
int n,m,d[maxn],f[maxn][50];
int N = 0,vis[maxn];
vector<int> son[maxn];
void dfs(int u,int fa,int dep){
d[u] = d[fa]+1;
f[u][0] = fa;
vis[u] = 1;
for(int i = 1; i <= N;i++) f[u][i] = f[f[u][i-1]][i-1];
for(int i=0;i<son[u].size();i++){
int v = son[u][i];
if(!vis[v]){
dfs(v,u,dep+1);
}
}
}
void init(){
for(N=0;(N+1) << 1<n;N++);
dfs(1,0,1);
}
int lca(int a,int b){
if(d[a] < d[b]){
swap(a,b);
}
for(int i=N;i>=0;i--){
if(d[f[a][i]] >= d[b]){
a = f[a][i];
}
}
if(a == b){
return b;
}
for(int i=N;i>=0;i--){
if(f[a][i] != f[b][i]){
a = f[a][i];
b = f[b][i];
}
}
return f[a][0];
}
int main(){
cin >> n>> m;
for(int i=1;i<=m;i++){
int u,v;
cin >> u >> v;
son[u].push_back(v);
son[v].push_back(u);
}
init();
while(1){
int u,v;
cin >> u >> v;
cout <<lca(u,v) << endl;
}
}
//2.欧拉序求lca
#include<iostream>
using namespace std;
#include<vector>
const int maxn = 1e6+5;
int cnt = 0;
int dfn[maxn];
int pos[maxn];
int vis[maxn];
vector<int> son[maxn];
void dfs(int u){
dfn[++cnt] = u;
pos[u] = cnt;
vis[u] = 1;
for(int i=0;i<son[u].size();i++){
int v = son[u][i];
if(!vis[v]) dfs(v);
dfn[++cnt] = u;
}
}
int main(){
int n,m;
cin >> n >> m;
for(int i=1;i<=m;i++){
int u,v;
cin >>u >> v;
son[u].push_back(v);
son[v].push_back(u);
}
dfs(1);
int k;
cin >> k;
for(int i=1;i<=k;i++){
int u,v;
cin >>u >> v;
int m = 999999; // m无穷大
int lca;
for(int j=min(pos[u],pos[v]);j<=max(pos[u],pos[v]);j++){
if(m > pos[dfn[j]]){
m = pos[dfn[j]];
lca = dfn[j];
}
}
cout << lca <<endl;
}
}
//3.tarjan算法 离线
#include<iostream>
using namespace std;
#include<vector>
const int maxn = 1e6+5;
vector<int > son[maxn];
int ans[maxn],vis[maxn];
int fa[maxn],head[maxn],cnt = 0;
struct Edge{
int to,next,id;
};
Edge edge[maxn];
int find(int x){
if(fa[x] != x) fa[x] = find(fa[x]);
return fa[x];
}
void merge(int a,int b){
int x = find(a);
int y = find(b);
if(x == y){
return;
}
fa[y] = x;
}
void add(int u,int v,int id){
edge[++cnt].to = v;
edge[cnt].next = head[u];
edge[cnt].id = id;
head[u] = cnt;
}
void dfs(int u,int f){
for(int i=0;i<son[u].size();i++){
int v = son[u][i];
if( v == f ) continue;
dfs(v,u);
merge(u,v);
}
vis[u] = 1;
for(int i=head[u];i;i=edge[i].next){
int v = edge[i].to;
int id = edge[i].id;
if(vis[v]) ans[id] = find(v);
}
}
int main(){
int n,m;
cin >> n >> m;
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i=1;i<=m;i++){
int u,v;
cin >>u >> v;
son[u].push_back(v);
son[v].push_back(u);
}
int k;
cin >> k;
for(int i=1;i<=k;i++){
int u,v;
cin >>u >> v;
add(u,v,i);
add(v,u,i);
}
dfs(1,0);
for(int i=1;i<=k;i++){
cout << ans[i] << endl;
}
}
//还可以用树链剖分求lca 以后会添的