• 最近公共祖先


    hiho1067

    题目链接

    问树上两个点的最近公共祖先

    -------------------------------------------------------------------------------------------------------

    第一次写所谓的离线算法,不是来一个询问就处理一下,而是在扫描树的过程中每扫到一个点就处理和这个点相关的询问。

    因为这个点的祖先肯定都访问过一次了,且所有标记为1的点都是这个点的祖先

    第一次扫到这个点时标记为1,扫完这个点的所有子节点后标记为2;

    关于当前点a的询问有三种情况:

    1.另外一个点b的标记为0,暂时无法判断;

    2.另外一个点b的标记为1,说明b为a的祖先,输出b;

    3.另外一个点b的标记为2,找到离b最近的标记为1的点;

    关于3,采用并查集维护,开始时每个点的[最近标记为1的点]都设成自己。从叶子向上,每标记一个点为2时,就把他及他的子孙挂到他的父节点上。

    注意:扫到一个点的时候一定要先处理和它相关的询问,然后再dfs这个节点,如果先dfs这个节点,再处理询问会出错。因为这个时候他的标记变成2了,他已经挂到父节点上了,如果询问他及他的子孙节点的最近祖先应该返回他,但是这时会返回他的父亲。

    #include <set>
    #include <map>
    #include <stack>
    #include <queue>
    #include <cmath>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>

    #define MAX(a,b) ((a)>=(b)?(a):(b))
    #define MIN(a,b) ((a)<=(b)?(a):(b))
    #define OO 0x0fffffff
    using namespace std;
    typedef long long LL;
    const int N = 100100;
    struct Edge{ int to,next,id; };
    int father[N];
    int ans[N],vis[N];
    int headsq[N],headst[N];
    Edge tree[N*2],query[N*2];
    int eidq = 0;
    int eidt = 0;
    void addQuery(int a,int b,int id){
        query[eidq].to = b;
        query[eidq].next = headsq[a];
        query[eidq].id = id;
        headsq[a] = eidq++;
        query[eidq].to = a;
        query[eidq].next = headsq[b];
        query[eidq].id = id;
        headsq[b] = eidq++;
        ans[id]=-1;
    }
    void addEdge(int a,int b){
        tree[eidt].to = b;
        tree[eidt].next = headst[a];
        headst[a] = eidt++;
    }
    int find(int id){
        int fid = father[id];
        if(fid==id) return fid;
        return (father[id] = find(fid));
    }
    void dfs(int id,int fid){
        for(int curId=headst[id];curId!=-1;curId=tree[curId].next){
            int to = tree[curId].to;
            vis[to] = 1;
            for(int qid=headsq[to];qid!=-1;qid=query[qid].next){
                if(ans[query[qid].id]!=-1) continue;
                int curq = query[qid].to;
                if(vis[curq]==1) {
                    ans[query[qid].id]=curq;
                }
                else if(vis[curq]==2){
                    ans[query[qid].id]=find(curq);
                }
            }
            dfs(to,id);
        }
        vis[id] = 2;
        father[id] = father[fid];
    }


    int n,m;
    int id1,id2;
    map<string,int> m1;
    map<int,string> m2;
    char name1[64],name2[64];
    int main(){
        memset(vis,0,sizeof(vis));
        memset(headsq,-1,sizeof(headsq));
        memset(headst,-1,sizeof(headst));

        cin>>n;
        int cnt = 0;
        for(int i=0;i<n;i++){
            cin>>name1>>name2;
            if(!(m1.count(name1))){
                m1[name1] = cnt;
                m2[cnt] = name1;
                id1 = cnt++;
            }
            else id1 = m1[name1];
            if(!(m1.count(name2))){
                m1[name2] = cnt;
                m2[cnt] = name2;
                id2 = cnt++;
            }
            else id2 = m1[name2];
            addEdge(id1,id2);
        }
        cin>>m;
        for(int i=0;i<m;i++){
            cin>>name1>>name2;
            addQuery(m1[name1],m1[name2],i);
        }

        for(int i=0;i<=n;i++) father[i]=i;

        vis[0]=1;
        dfs(0,0);

        for(int i=0;i<m;i++){
            cout<<m2[ans[i]]<<endl;
        };

        return 0;
    }

  • 相关阅读:
    java输入一个文件夹,查找出所有的文件列表
    java字节流到字符流的桥梁InputStreamReader,OutputStreamWriter
    java中获取用户输入字符,并将字符大写后显示
    mqtt
    tcpcopy
    lmax disruptor
    delete solr index
    http://book.douban.com/doulist/2545443/
    http://www.dottoro.com/
    最值得学习阅读的10个C语言开源项目代码
  • 原文地址:https://www.cnblogs.com/redips-l/p/6913997.html
Copyright © 2020-2023  润新知