[模板] LCA

离线tarjan(dfs)
链式前向星从1开始存,免了赋-1初值,方便异或运算,好处多多。
并查集fa数组的初始化可以写入dfs中顺便执行,少一个大循环。

数组要开大,不然会报WA,可能它在乱搜吧。

//Writer:GhostCai && His Yellow Duck

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int MAXN=2000000;

int m,n,root;

inline int read_d(){
    int i=0;
    char c;
    while(c=getchar(),c<'0'||c>'9');
    while(c<='9'&&c>='0'){
        i=i*10+c-'0';
        c=getchar();
    }
    return i;
}

int fa[MAXN];
int fnd(int x){
    return fa[x]==x?x:fa[x]=fnd(fa[x]);
}
inline void cat(int x,int y){
    x=fnd(x);y=fnd(y);
    fa[y]=x;
}

struct Ques{
    int next,id,lca;
}qs[MAXN];
int qhead[MAXN],qcnt=1;
inline void qadd(int x,int y){
    qs[++qcnt].id = y;
    qs[qcnt].next = qhead[x];
    qhead[x]=qcnt;
}


struct Edge{
    int next,to;
}e[MAXN];
int head[MAXN],ecnt=1;
inline void add(int x,int y){
    e[++ecnt].next = head[x];
    e[ecnt].to = y;
    head[x]=ecnt;
}

bool vis[MAXN];
int dfs(int id){
    vis[fa[id]=id]=1;
//  fa[id]=id;
    for(int i=head[id];i;i=e[i].next){
        int v=e[i].to ;
        if(vis[v]) continue;
        dfs(v);
        cat(id,v);
    }
    for(int i=qhead[id];i;i=qs[i].next){
        int v=qs[i].id ;
        if(!vis[v]) continue;
        qs[i^1].lca = qs[i].lca = fnd(v);
//      if(i%2) qs[i+1].lca = qs[i].lca ;
//      else qs[i-1].lca = qs[i].lca ;
    }
}

int main(){
    int  x,y;
//  cin>>n>>m>>root;
    scanf("%d%d%d",&n,&m,&root);
//  for(int i=1;i<=n;i++) fa[i]=i;
//  memset(head,-1,sizeof(head));
//  memset(qhead,-1,sizeof(qhead));
    for(int i=1;i<=n-1;i++){
//      cin>>x>>y;
//      x=read_d();
//      y=read_d();
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    for(int i=1;i<=m;i++){
//      cin>>x>>y;
//      x=read_d();
//      y=read_d();
        scanf("%d%d",&x,&y);
        qadd(x,y);
        qadd(y,x);
    }
    dfs(root);
    for(int i=1;i<=m;i++){
        printf("%d
",qs[i<<1].lca);
    }
}

在线 倍增求法
洛谷模板题cin会T,偷懒写builtin

//Writer:GhostCai && His Yellow Duck

#include<iostream>
#include<cmath>
using namespace std;

const int MAXN=1000000;

int n,m,root;
int dep[MAXN],f[MAXN][32];
int len;

struct Edge{
    int next,to;
}e[MAXN];
int head[MAXN],ecnt=1;
inline void add(int x,int y){
    e[++ecnt].to = y;
    e[ecnt].next = head[x];
    head[x] = ecnt;
} 

void dfs(int now,int pre){
    dep[now]=dep[pre]+1;
    f[now][0]=pre;
    for(int i=head[now];i;i=e[i].next){
        int v=e[i].to ;
        if(v==pre) continue;
        dfs(v,now);
    }
}

void redouble(){
    for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i<=n;i++){
            if(dep[i]-(1<<j)<0) continue;
            f[i][j]=f[f[i][j-1]][j-1];
        }
    }

} 

int query(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
//  for(int i=len;i>=0;i--){
//      if(dep[x]-(1<<i)<dep[y]) continue;
//      x=f[x][i];//
//  }
//  ======================================
//  int d=dep[x]-dep[y];
//  while(d){
//      x=f[x][(int)log2(d&(-d))];
//      d-=d&(-d);
//  }
//  ======================================
    int d=dep[x]-dep[y],k=0;
    while(d){
        if(d&1) x=f[x][k];
        k++;
        d>>=1;
    }
    if(x==y) return x;///////
    for(int i=len;i>=0;i--){
        if(f[x][i]==f[y][i]) continue;
        x=f[x][i]; y=f[y][i];
    }
    return f[x][0];
}


int main(){
    cin.sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>m>>root;
    len=log(n)/log(2);
    for(int i=1;i<=n-1;i++){
        int x,y;
        cin>>x>>y;
        add(x,y);
        add(y,x);
    }
    dfs(root,0);
    redouble();
    for(int i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
        cout<<query(x,y)<<endl;
    }
    return 0;
}

树剖,极其好写,还是在线查询,常数小,速度媲美tarjan。

#include<iostream>
#include<cstdio>

using namespace std;

const int MAXN=500005;

int n,m,st;

inline int rd(){
  int ret=0,f=1;char c;
  while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
  while(isdigit(c))ret=ret*10+c-'0',c=getchar();
  return ret*f;
}

struct Edge{
  int next,to,w;
}e[MAXN<<1];
int ecnt,head[MAXN];
inline void add(int x,int y,int w){
  e[++ecnt].to = y;
  e[ecnt].w = w;
  e[ecnt].next = head[x];
  head[x] = ecnt;
}

int fa[MAXN],dep[MAXN],siz[MAXN],hch[MAXN];
void dfs1(int cur,int pre){
  fa[cur]=pre;dep[cur]=dep[pre]+1;siz[cur]=1;
  int mx=-1;
  for(int i=head[cur];i;i=e[i].next){
    int v=e[i].to;
    if(v==pre) continue;
    dfs1(v,cur);
    siz[cur]+=siz[v];
    if(siz[v]>mx) hch[cur]=v,mx=siz[v];
  }
}
int id[MAXN],top[MAXN],cnt;
void dfs2(int cur,int tp){
  id[cur]=++cnt;top[cur]=tp;
  if(hch[cur]) dfs2(hch[cur],tp);
  for(int i=head[cur];i;i=e[i].next){
    int v=e[i].to;
    if(v==fa[cur]||v==hch[cur]) continue;//
    dfs2(v,v);
  }
}

int lca(int x,int y){
  while(top[x]!=top[y]){
    dep[top[x]]>=dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
  }
  return dep[x]<=dep[y]?x:y;
}

int main(){
  n=rd();m=rd();st=rd();
  int x,y;
  for(int i=1;i<=n-1;i++){
    x=rd();y=rd();
    add(x,y,1);add(y,x,1);
  }
  dfs1(st,0);
  dfs2(st,st);
  for(int i=1;i<=m;i++){
    x=rd();y=rd();
    printf("%d
",lca(x,y));
  }
  return 0;
}

本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9247491.html

原文地址:https://www.cnblogs.com/ghostcai/p/9247491.html