zoukankan      html  css  js  c++  java
  • LCA【Tarjan】

    首先,我们先来了解LCA。

    LCA 是树上两个点最近的公共祖先。

    比如说,在如图的树中,3与4的公共祖先有“2”,“1”,但最近的祖先是“2”。

    显然,暴力可以做O(n),但是我们希望更快。

    现在,有两种方法:

      1)在线操作,但这需要“倍增”,再此不讨论。

      2)离线操作,使用Tarjan与并查集。

    先给出操作方法:

    DFS (u)
       for i in u.son
          DFS(i)
          UNION(u,i)
       for i in u.e # e 表示 e 与访问所有和u有询问关系的i
          if i.vis
             (u,i).LCA = find(i)

    可以发现,操作是在深搜中进行的。下面开始模拟。

    初始值:

    f[1]=1; vis[1]=0;
    f[2]=2; vis[2]=0;
    f[3]=3; vis[3]=0;
    f[4]=4; vis[4]=0;
    f[5]=5; vis[5]=0;
    f[6]=6; vis[6]=0;

    第一次操作后:

    f[1]=1; vis[1]=0;
    f[2]=2; vis[2]=0;
    f[3]=2; vis[3]=1;
    f[4]=4; vis[4]=0;
    f[5]=5; vis[5]=0;
    f[6]=6; vis[6]=0;

    第二次操作后:

    f[1]=1; vis[1]=0;
    f[2]=2; vis[2]=1;
    f[3]=2; vis[3]=1;
    f[4]=2; vis[4]=1
    f[5]=5; vis[5]=0;
    f[6]=6; vis[6]=0;

     第三次操作后:

    f[1]=1; vis[1]=1;
    f[2]=2; vis[2]=1;
    f[3]=2; vis[3]=1;
    f[4]=2; vis[4]=1;
    f[5]=1; vis[5]=1;
    f[6]=5; vis[6]=1;

     另附代码:

    #include <iostream>  
    #include <stdio.h>  
    #include <algorithm>  
    #include <string.h>  
    using namespace std;  
      
    const int maxn=10010;
    const int maxq=100;   
    int f[maxn];
    int find(int x)  
    {  
        if(f[x]==-1)  
            return x;  
        return f[x]=find(f[x]);  
    }  
    void unite(int u,int v)  
    {  
        int x=find(u);  
        int y=find(v);  
        if(x!=y)  
            f[x]=y;  
    }  
      
    bool vis[maxn];
    int ancestor[maxn];
    struct Edge  
    {  
        int to,next;  
    }edge[maxn*2];  
    int head[maxn],tot;  
    void addedge(int u,int v)
    {  
        edge[tot].to=v;  
        edge[tot].next=head[u];  
        head[u]=tot++;  
    }  
      
    struct Query  
    {  
        int q,next;  
        int index; 
    }query[maxq*2];  
    int ans[maxn*2];
    int h[maxn],tt;  
    int Q;
      
    void addquery(int u,int v,int index)
    {  
        query[tt].q=v;  
        query[tt].next=h[u];  
        query[tt].index=index;  
        h[u]=tt++;  
        query[tt].q=u;
        query[tt].next=h[v];  
        query[tt].index=index;  
        h[v]=tt++;  
    }  
      
    void init()  
    {  
        tot=0;  
        memset(head,-1,sizeof(head));  
        tt=0;  
        memset(h,-1,sizeof(h));  
        memset(vis,0,sizeof(vis));  
        memset(f,-1,sizeof(f));  
        memset(ancestor,0,sizeof(ancestor));  
    }  
      
    void LCA(int u)  
    {  
        ancestor[u]=u;  
        vis[u]=true;  
        for(int i=head[u];i!=-1;i=edge[i].next) 
        {  
            int v=edge[i].to;  
            if(vis[v])  
                continue;  
            LCA(v);  
            unite(u,v);  
            ancestor[find(u)]=u;
        }  
        for(int i=h[u];i!=-1;i=query[i].next)
        {  
            int v=query[i].q;  
            if(vis[v])  
                ans[query[i].index]=ancestor[find(v)];  
        }  
    }  
    bool flag[maxn];
      
    int t;  
    int n,u,v;  
      
    int main()  
    {  
        cin >> n;  
        init();  
        memset(flag,0,sizeof(flag));  
        for(int i=1;i<n;i++)  
        {  
            cin >> u >> v; 
            flag[v]=true; 
            addedge(u,v);  
            addedge(v,u);  
        }  
        cin >> Q;
        for(int i=0;i<Q;i++)  
        {  
            scanf("%d%d",&u,&v);  
            addquery(u,v,i);  
        }  
        int root;  
        cin >> root;
        LCA(root);  
        for(int i=0;i<Q;i++)  
            printf("%d ",ans[i]);  
        return 0;  
    }  
  • 相关阅读:
    跟面试官聊.NET垃圾收集,直刺面试官G点
    基于.net开发chrome核心浏览器【五】
    HTTP和HTTPS的区别(转)
    Java多线程
    Java常用设计模式
    MVC详解(转)
    java的反射机制浅谈(转)
    进程、线程与处理器的调度(转)
    请简单介绍一下什么是Spring?
    面向对象三大特性概述[封装、继承、多态](转)
  • 原文地址:https://www.cnblogs.com/dgklr/p/8476170.html
Copyright © 2011-2022 走看看