• 【算法】【LCA】【tarjan】【倍增】


    呃,这个常用但是我一直不会

    Tarjan

      Tarjan 算法基于 dfs ,在 dfs 的过程中,对于每个节点位置的询问做出相应的回答。

      dfs 的过程中,当一棵子树被搜索完成之后,就把他和他的父亲合并成同一集合;在搜索当前子树节点的询问时,如果该询问的另一个节点已经被访问过,那么该编号的询问是被标记了的,于是直接输出当前状态下,另一个节点所在的并查集的祖先;如果另一个节点还没有被访问过,那么就做下标记,继续 dfs 。

    //tarjian,边建边 边回答问题
    #include<cstdio>
    #include<cstdlib>
    #include<vector>
    using namespace std;
    int n,m,rt;
    const int N=500003,M=500003;
    int ans[M];
    vector <int> e[N];
    struct node
    {
        int v,id;
        node(int vv,int ii)
        { v=vv,id=ii; }
        node(){}
    };
    vector <node> q[N];
    
    int fa[N];
    int find(int x)
    { return fa[x]==0?x:fa[x]=find(fa[x]); }
    bool vis[N];
    void dfs(int x,int f)
    {
        int sz=e[x].size();
        for(int i=0;i<sz;i++)
        {
            int v=e[x][i];
            if(v!=f) dfs(v,x),fa[v]=x;
        }
        vis[x]=true;
        
        sz=q[x].size();
        for(int i=0;i<sz;i++)
        {
            int v=q[x][i].v ;
            if(!ans[q[x][i].id ] && vis[v])
                ans[q[x][i].id ]=find(v);
        }
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&rt);
        int u,v;
        for(int i=1;i<n;i++) 
            scanf("%d%d",&u,&v),e[u].push_back(v),e[v].push_back(u);
        for(int i=0;i<m;i++)
            scanf("%d%d",&u,&v),q[u].push_back(node(v,i)),q[v].push_back(node(u,i));
        
        dfs(rt,0);
        
        for(int i=0;i<m;i++) printf("%d
    ",ans[i]);
        
        return 0;
    } 

    倍增

    就从父亲更新到儿子

    #include<cstdio>
    #include<cstdlib>
    #include<vector>
    #include<algorithm>
    using namespace std;
    int n,q;
    const int N=100003,Q=10003;
    int fa[N][21],dep[N];//辅助数组dep 
    vector <int > g[N]; 
    bool tag[N];
    
    void dfs(int x)
    {
        dep[x]=dep[fa[x][0]]+1;
        for(int i=1;i<21;i++)
            fa[x][i]=fa[fa[x][i-1]][i-1];
            
        int sz=g[x].size() ;
        for(int i=0;i<sz;i++)
            dfs(g[x][i]);
    }
    int lg[N];
    void get_log()
    {
        for(int i=1;i<n;i++)
            lg[i]=lg[i-1]+(i==(1<<(lg[i-1])));//这里是看最高位,是第几位(第一位表示二进制中第0位) 
    }
    int LCA(int u,int v)
    {
        if(dep[u]<dep[v]) swap(u,v); 
        int dis=dep[u]-dep[v];
        for(int i=1,j=0;dis;i<<=1,j++)
            if(dis&i)
            {
                dis^=i;
                u=fa[u][j];
            }
        if(u==v) return u;
        
        for(int i=lg[dep[u]]-1;i>=0;i--)
            if(fa[u][i]!=fa[v][i])
                u=fa[u][i],v=fa[v][i];
        return fa[u][0];
    }
    
    int main()
    {
        scanf("%d",&n);
        int u,v;
        for(int i=1;i<n;i++)
            scanf("%d%d",&u,&v),fa[v][0]=u,g[u].push_back(v),tag[v]=true;
        for(int i=1;i<=n;i++)
            if(!tag[i])
            {
                dfs(i);
                break;
            }
        
        get_log();
        scanf("%d",&q); 
        while(q--)
        {
            scanf("%d%d",&u,&v);
            printf("%d
    ",LCA(u,v));
        }
        
        return 0;
    } 
  • 相关阅读:
    Ubuntu下RabbitMq 安装与运行
    web_api所需包
    Ubuntu16.04下安装python3.6.4详细步骤
    JavaScript
    css
    html
    MySQL
    day4 函数
    day3 字典,集合,文件
    day2
  • 原文地址:https://www.cnblogs.com/xwww666666/p/11327012.html
Copyright © 2020-2023  润新知