LCA的五种解法

标准求法

//O(nlogn)-O(logn)
#include<cstdio>
#include<algorithm> 
using namespace std;
const int maxn=100010;
int first[maxn],next[maxn*2],to[maxn*2],dis[maxn*2];
int n,m;
void AddEdge(int a,int b,int c)
{
     to[++m]=b;
     dis[m]=c;
     next[m]=first[a];
     first[a]=m;
}
int dep[maxn],fa[maxn],cost[maxn],anc[20][maxn];
void dfs(int x)
{
    dep[x]=dep[fa[x]]+1;
    for(int i=first[x];i;i=next[i])
    {
       if(to[i]!=fa[x])
       {
           fa[to[i]]=x;
           cost[to[i]]=cost[x]+dis[i];
           dfs(to[i]);
       }
    }
}
void preprocess()
{
    for(int i=1;i<=n;i++) anc[0][i]=fa[i];
    for(int j=1;(1<<j)<=n;j++)
       for(int i=1;i<=n;i++)
          if(anc[j-1][i])
          {
              int a=anc[j-1][i];
              anc[j][i]=anc[j-1][a];
          }
}
int LCA(int p,int q)
{
    if(dep[p]<dep[q]) swap(p,q);
    int log=1;
    for(;(1<<log)<=dep[p];log++); log--;
    for(int i=log;i>=0;i--) if(dep[p]-dep[q]>=(1<<i)) p=anc[i][p];
    if(p==q) return p;
    for(int i=log;i>=0;i--)
       if(anc[i][p]!=anc[i][q])
       {
           p=anc[i][p];
           q=anc[i][q];
       }
    return fa[p];
}
int main()
{
    int a,b,c,Q;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        AddEdge(a,b,c);
        AddEdge(b,a,c);
    }
    scanf("%d",&Q);
    dfs(1);
    preprocess();
    while(Q--)
    {
        scanf("%d%d",&a,&b);
        c=LCA(a,b);
        printf("%d %d
",dep[a]+dep[b]-dep[c]*2+1,cost[a]+cost[b]-cost[c]*2);
    }
    return 0;
}
View Code

欧拉序列套区间最小值

//O(nlogn)-O(1)
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=100010;
int n,e=1;
int first[maxn],next[maxn*2],dis[maxn*2],to[maxn*2];
void AddEdge(int a,int b,int c)
{
    to[e]=b;
    dis[e]=c;
    next[e]=first[a];
    first[a]=e++;
} 
int fa[maxn],dep[maxn],d[maxn],p[maxn],A[maxn*2],z=1;
void dfs(int x)
{
    dep[x]=dep[fa[x]]+1;
    p[x]=z; A[z++]=x;
    for(int i=first[x];i;i=next[i])
    {
        if(fa[x]!=to[i])
        {
            d[to[i]]=d[x]+dis[i];
            fa[to[i]]=x;
            dfs(to[i]);
            A[z++]=x;
        }
    }
}
int mv[20][maxn*2],len[maxn*2];
void RMQ_init(int m)
{
    for(int i=1;i<=m;i++) mv[0][i]=A[i];
    for(int j=1;(1<<j)<=m;j++)
       for(int i=1;i+(1<<j)<=m+1;i++)
       {
           mv[j][i]=mv[j-1][i];
           if(dep[mv[j-1][i]]>dep[mv[j-1][i+(1<<(j-1))]]) mv[j][i]=mv[j-1][i+(1<<(j-1))];
       }
    for(int i=1;i<=m;i++)
       while(1<<(len[i]+1)<=i) len[i]++;
}
int LCA(int a,int b)
{
    if(a<b) swap(a,b);
    int k=len[a-b+1];
    return dep[mv[k][b]]<dep[mv[k][a-(1<<k)+1]]?mv[k][b]:mv[k][a-(1<<k)+1];
}
int main()
{
    int a,b,c,Q;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        AddEdge(a,b,c);
        AddEdge(b,a,c); 
    } 
    dfs(1);
    RMQ_init(z-1);
    scanf("%d",&Q);
    while(Q--)
    {
        scanf("%d%d",&a,&b);
        c=LCA(p[a],p[b]);
        printf("%d %d
",dep[a]+dep[b]-2*dep[c]+1,d[a]+d[b]-2*d[c]);
    }
    return 0;
} 
View Code

树链剖分

//O(n)-O(logn)
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100010;
struct Edge
{
    int b,c;
}es[maxn*2];
int n,m=1;
int first[maxn],next[maxn*2];
void AddEdge(int a,int b,int c)
{
    es[m]=(Edge){b,c};
    next[m]=first[a];
    first[a]=m++;
}
int dep[maxn],siz[maxn],son[maxn],fa[maxn],dis[maxn];
void dfs(int x)
{
    siz[x]=1; dep[x]=dep[fa[x]]+1;
    for(int i=first[x];i;i=next[i])
    {
       Edge& e=es[i];
       if(e.b!=fa[x])
       {
          fa[e.b]=x;
          dis[e.b]=dis[x]+e.c;
          dfs(e.b);
          siz[x]+=siz[e.b];
          if(siz[son[x]]<siz[e.b]) son[x]=e.b;
       }
    }
}
int top[maxn];
void build(int x)
{
    if(son[x]) 
    {
       top[son[x]]=top[x];
       build(son[x]);
    }
    for(int i=first[x];i;i=next[i])
    {
       Edge& e=es[i];
       if(e.b!=fa[x]&&e.b!=son[x])
       {
           top[e.b]=e.b;
           build(e.b);
       }
    }
}
int query(int va,int vb)
{
     int f1=top[va],f2=top[vb];
     while(f1!=f2)
     {
         if(dep[f1]<dep[f2])
         {
            swap(f1,f2);
            swap(va,vb);
         }
         va=fa[f1]; f1=top[va];
     }
     if(dep[va]>dep[vb]) swap(va,vb);
     return va;
}
int main()
{
    int a,b,c,Q;
    scanf("%d",&n);
    for(int i=1;i<n;i++) 
    {
       scanf("%d%d%d",&a,&b,&c);
       AddEdge(a,b,c);
       AddEdge(b,a,c);
    }
    dfs(1);
    top[1]=1;
    build(1);
    scanf("%d",&Q);
    while(Q--)
    {
        scanf("%d%d",&a,&b);
        c=query(a,b);
        printf("%d %d
",dep[a]+dep[b]-2*dep[c]+1,dis[a]+dis[b]-2*dis[c]);
    }
    return 0;
}
View Code

Tarjan算法(离线)

//O(n)-O(1)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010;
int n,m;
int first[maxn],next[maxn*2],to[maxn*2],d[maxn*2];
void AddEdge(int a,int b,int c)
{
    to[++m]=b;
    d[m]=c;
    next[m]=first[a];
    first[a]=m;
}
int f2[maxn],n2[maxn*2],v[maxn*2],id[maxn*2];
void AddQuery(int a,int b,int c)
{
    v[++m]=b;
    id[m]=c;
    n2[m]=f2[a];
    f2[a]=m;
}
int vis[maxn],dis[maxn],dep[maxn],f[maxn],ans[maxn];
int findset(int x) {return x==f[x]?x:f[x]=findset(f[x]);}
void dfs(int x,int fa)
{
    f[x]=x; dep[x]=dep[fa]+1;
    for(int i=first[x];i;i=next[i])
    {
        if(to[i]!=fa)
        {
            dis[to[i]]=dis[x]+d[i];
            dfs(to[i],x);
            f[to[i]]=f[x];
        }
    }
    vis[x]=1;
    for(int i=f2[x];i;i=n2[i]) if(vis[v[i]]) ans[id[i]]=findset(v[i]); 
}
int A[maxn],B[maxn];
int main()
{
    scanf("%d",&n);
    int a,b,c,Q;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        AddEdge(a,b,c);
        AddEdge(b,a,c);
    }
    scanf("%d",&Q);
    m=0;
    for(int i=0;i<Q;i++)
    {
        scanf("%d%d",&A[i],&B[i]);
        AddQuery(A[i],B[i],i);
        AddQuery(B[i],A[i],i);
    }
    dfs(1,0);
    for(int i=0;i<Q;i++) printf("%d %d
",dep[A[i]]+dep[B[i]]-dep[ans[i]]*2+1,dis[A[i]]+dis[B[i]]-dis[ans[i]]*2);
    return 0;
}
View Code

LCT

//O(n)-O(logn)
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=100010;
int n,m;
int first[maxn],next[maxn*2],to[maxn*2],d[maxn*2];
void AddEdge(int a,int b,int c)
{
    to[++m]=b;
    d[m]=c;
    next[m]=first[a];
    first[a]=m;
}
int ans1,ans2;
struct LCT
{
    int pre[maxn],ch[maxn][2],fa[maxn],v[maxn],sumv[maxn],s[maxn];
    void init()
    {
        memset(pre,0,sizeof(pre));
        memset(ch,0,sizeof(ch));
        s[0]=fa[1]=v[0]=sumv[0]=0;
    }
    void maintain(int x)
    {
        sumv[x]=v[x]+sumv[ch[x][0]]+sumv[ch[x][1]];
        s[x]=s[ch[x][0]]+s[ch[x][1]]+1;
    }
    void rotate(int x,int d)
    {
        int y=pre[x],z=pre[y];
        ch[y][d^1]=ch[x][d];
        pre[ch[x][d]]=y;
        ch[z][ch[z][1]==y]=x;
        pre[x]=z;
        ch[x][d]=y;
        pre[y]=x;
        maintain(y);
    }
    void splay(int x)
    {
        int rt=x;
        while(pre[rt]) rt=pre[rt];
        if(rt!=x)
        {
            fa[x]=fa[rt];
            fa[rt]=0;
            while(pre[x]) rotate(x,ch[pre[x]][0]==x);
        }
        maintain(x);
    }
    void access(int x)
    {
        int y=0;
        for(;x;x=fa[x])
        {
            splay(x);
            fa[ch[x][1]]=x;
            pre[ch[x][1]]=0;
            ch[x][1]=y;
            fa[y]=0;
            pre[y]=x;
            y=x;
            maintain(x);
        }
    }
    void query(int x,int y)
    {
        access(y);
        for(y=0;x;x=fa[x])
        {
            splay(x);
            if(!fa[x])
            {
                ans1=s[ch[x][1]]+s[y]+1;
                ans2=sumv[ch[x][1]]+sumv[y];
                return;
            }
            fa[ch[x][1]]=x;
            pre[ch[x][1]]=0;
            ch[x][1]=y;
            fa[y]=0;
            pre[y]=x;
            y=x;
            maintain(x);
        }
    }
}sol;
int vis[maxn];
queue<int> Q;
void BFS(int x)
{
    vis[1]=1; Q.push(1);
    while(!Q.empty())
    {
        x=Q.front(); Q.pop();
        for(int i=first[x];i;i=next[i])
            if(!vis[to[i]])
            {
                vis[to[i]]=1;
                sol.fa[to[i]]=x;
                sol.v[to[i]]=d[i];
                Q.push(to[i]);
                sol.maintain(to[i]);
            }
    }
}
int main()
{
    scanf("%d",&n);
    int a,b,c,Q;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        AddEdge(a,b,c);
        AddEdge(b,a,c);
    }
    sol.init();
    BFS(1);
    scanf("%d",&Q);
    while(Q--)
    {
        scanf("%d%d",&a,&b);
        sol.query(a,b);
        printf("%d %d
",ans1,ans2);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/4523039.html