zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    elasticsearch索引的增删改查入门
    windows下mongodb安装与使用
    在SqlServer中使用Try Catch(转)
    sqlserver 存储过程 try catch TRANSACTION (转)
    SQLserver2008如何把表格变量传递到存储过程中
    SQL对字符串数组的处理
    SQLSERVER数据库表各种同步技术
    函数参数
    闭包
    枚举
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/4523039.html
Copyright © 2011-2022 走看看