zoukankan      html  css  js  c++  java
  • bryce1010专题训练——LCA

    1、Targan算法(离线)

    http://poj.org/problem?id=1470

    /*伪代码
    Tarjan(u)//marge和find为并查集合并函数和查找函数
    {
        for each(u,v)    //访问所有u子节点v
        {
            Tarjan(v);        //继续往下遍历
            marge(u,v);    //合并v到u上
            标记v被访问过;
        }
        for each(u,e)    //访问所有和u有询问关系的e
        {
            如果e被访问过;
            u,e的最近公共祖先为find(e);
        }
    }
    
    */
    //思想
    /*
    1.任选一个点为根节点,从根节点开始。
    2.遍历该点u所有子节点v,并标记这些子节点v已被访问过。
    3.若是v还有子节点,返回2,否则下一步。
    4.合并v到u上。
    5.寻找与当前点u有询问关系的点v。
    6.若是v已经被访问过了,则可以确认u和v的最近公共祖先为v被合并到的父亲节点a。
    */
    
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<stdio.h>
    #include<math.h>
    using namespace std;
    #define ll long long
    
    
    const int MAXN=1010;
    const int MAXQ=500010;
    
    //并查集部分
    int F[MAXN];//初始化为-1
    int find(int x)
    {
        if(F[x]==-1)return x;
        return F[x]=find(F[x]);
    }
    //merge
    void bing(int u,int v)
    {
        int t1=find(u);
        int t2=find(v);
        if(t1!=t2)
        {
            F[t1]=t2;
        }
    }
    //****************
    //建图部分
    bool vis[MAXN];
    int ancestor[MAXN];//存储查询过程节点的祖先
    struct Edge
    {
        int to,next;
    }edge[MAXN<<2];
    int head[MAXN],tot;
    void add_edge(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<<1];
    
    int answer[MAXQ];//存储最后的每个查询的公共祖先,下标0,Q-1
    int h[MAXQ];
    int tt;int Q;
    
    void add_query(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++;
    }
    
    //LCA部分
    void init()
    {
        tot=0;
        memset(head,-1,sizeof(head));
        tt=0;
        memset(h,-1,sizeof(h));
        memset(vis,false,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);
            bing(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])
            {
                answer[query[i].index]=ancestor[find(v)];
            }
        }
    }
    
    bool flag[MAXN];
    int Count_num[MAXN];
    int main()
    {
        int n;
        int u,v,k;
        while(scanf("%d",&n)==1)
        {
            init();
            memset(flag,false,sizeof(flag));
            for(int i=1;i<=n;i++)
            {
                scanf("%d:(%d)",&u,&k);
                while(k--)
                {
                    scanf("%d",&v);
                    flag[v]=true;
                    add_edge(u,v);
                    add_edge(v,u);
                }
            }
            scanf("%d",&Q);
            for(int i=0;i<Q;i++)
            {
                char ch;
                cin>>ch;
                scanf("%d %d)",&u,&v);
                //cin>>ch;
                add_query(u,v,i);
            }
            int root;
            for(int i=1;i<=n;i++)//找到没有入度的点作为root
            {
                if(!flag[i])
                {
                    root=i;
                    break;
                }
            }
            LCA(root);
            memset(Count_num,0,sizeof(Count_num));
            for(int i=0;i<Q;i++)
            {
                Count_num[answer[i]]++;
            }
            for(int i=1;i<=n;i++)
            {
                if(Count_num[i]>0)
                {
                    printf("%d:%d
    ",i,Count_num[i]);
                }
            }
        }
    //    getchar();getchar();
        return 0;
    }
    
    
    
    /*
    5
    5:(3) 1 4 2
    1:(0)
    4:(0)
    2:(1) 3
    3:(0)
    6
    (1 5) (1 4) (4 2) (2 3) (1 3) (4 3)
    */
    
    

    2.带边权的Targan离线算法

    http://acm.hdu.edu.cn/showproblem.php?pid=2586

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    
    const int MAXN=40010;
    const int MAXQ=40010;
    
    int n;
    //并查集部分
    int F[MAXN];//初始为-1
    int find(int x)
    {
        if(F[x]==-1)return x;
        return F[x]=find(F[x]);
    }
    
    int bing(int u,int v)
    {
        int t1=find(u);
        int t2=find(v);
        if(t1!=t2)
        {
            F[t1]=t2;
        }
    }
    
    
    //建图部分
    bool vis[MAXN];
    int ancestor[MAXN];
    struct Edge
    {
        int to,next;
        int val;//每条边的权重
    }edge[MAXN<<2];
    int head[MAXN],tot;//head初始为-1
    
    void add_edge(int u,int v,int val)
    {
        edge[tot].next=head[u];
        edge[tot].to=v;
        edge[tot].val=val;
        head[u]=tot++;
    //    edge[tot].next=head[v];
    //    edge[tot].to=u;
    //    edge[tot].val=val;
    //    head[v]=tot++;
    }
    int dist[MAXN];
    bool flag[MAXN];
    //查询部分
    struct Query
    {
        int q,next;
        int index;//查询标号
    }query[MAXQ<<1];
    int answer[MAXQ];//存储每个查询的结果
    int h[MAXQ];
    int tt;
    int Q;
    void add_query(int u,int v,int index)
    {
        query[tt].next=h[u];
        query[tt].q=v;
        query[tt].index=index;
        h[u]=tt++;
        query[tt].next=h[v];
        query[tt].q=u;
        query[tt].index=index;
        h[v]=tt++;
    }
    
    
    
    //LCA部分
    void init()
    {
        tot=0;
        memset(F,-1,sizeof(F));
        memset(vis,false,sizeof(vis));
        memset(ancestor,0,sizeof(ancestor));
        memset(head,-1,sizeof(head));
        memset(h,-1,sizeof(h));
        memset(dist,0,sizeof(dist));
        memset(flag,false,sizeof(flag));
        tt=0;
    }
    void LCA(int u,int val)
    {
        ancestor[u]=u;
        vis[u]=true;
        dist[u]=val;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            int weight=edge[i].val;
            if(vis[v])continue;
            LCA(v,val+weight);
            bing(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])
            {
    //            cout<<ancestor[find(v)]<<endl;
                answer[query[i].index]=dist[v]+dist[u]-2*dist[ancestor[find(v)]];
            }
        }
    }
    
    int root;
    
    int main()
    {
        int T,u,v,val;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&Q);
            init();
            for(int i=1;i<n;i++)
            {
                scanf("%d%d%d",&u,&v,&val);
                flag[v]=true;
                add_edge(u,v,val);
                add_edge(v,u,val);
            }
            for(int i=0;i<Q;i++)
            {
                scanf("%d%d",&u,&v);
                add_query(u,v,i);
            }
            //找到没有入度的节点作为root
            for(int i=1;i<=n;i++)
                if(!flag[i])
                {
                    root=i;
                    break;
                }
            LCA(root,0);
            for(int i=0;i<Q;i++)
            {
                printf("%d
    ",answer[i]);
            }
        }
    
    
    
    }
    
    
    /*
    2
    3 2
    1 2 10
    3 1 15
    1 2
    2 3
    
    */
    
    
    
    
    
    
    
    
    
    
    
  • 相关阅读:
    缓存概述
    进程Process
    MVC系统过滤器、自定义过滤器
    暂无,进程那篇深度不够
    SeasLog 与 monolog 日志系统的区别,SeasLog安装步骤
    阿里面试官:说一下从url输入到返回请求的过程,问的难度就是不一样!
    [技术分享]OSI七层模型详解
    Mysql引擎介绍及InnoDB逻辑存储结构
    Paypal 实现自动订阅
    PayPal 支付Checkout 收银台和 Subscription 订阅计划全过程分享
  • 原文地址:https://www.cnblogs.com/bryce1010/p/9386825.html
Copyright © 2011-2022 走看看