zoukankan      html  css  js  c++  java
  • hicocoder1067 最近公共祖先·二(离线算法tarjan)

    tarjan算法是处理最近公共祖先问题的一种离线算法。

    算法思路:

    先将所有的询问搜集起来。

    然后对树进行dfs,在dfs的过程中对节点进行着色。当到达某个节点x的时候,给x着色为灰色,离开x的时候,着色为黑色。

    当到达x并将其着色为灰色后,处理与x相关联的所有询问:

    (这里有一个显然的事实:所有的灰色节点都是x的祖先)

    (1)若询问的另一个节点y是灰色,那么该询问的结果为y;

    (2)若询问的另一个节点y是黑色,那么询问结果应为离y最近的y的灰色祖先(因为所有灰色节点都是x的祖先,所以离y最近的y的灰色祖先就是x与y的最近公共祖先了);

    关键在于如何找到离y最近的y的灰色祖先:利用并查集,维护每个节点所属的集合,当某个节点被标记为黑色,就将该节点所在的子树合并到其父节点所属的集合。而灰色节点所属的集合编号就是该节点编号本身。这样我们利用并查集的查找操作就能快速的找到任意黑色节点的最近灰色祖先。

    (3)若询问的另一个节点y还没被着色,那么暂不处理,留待访问到y节点的时候再处理。

    我的代码:

      1 #include <iostream>
      2 #include <string>
      3 #include <map>
      4 #include <vector>
      5 #include <cstring>
      6 
      7 using namespace std;
      8 
      9 #define MAXN 100005
     10 
     11 map<string, int> mp;
     12 string name[2*MAXN];
     13 vector<int> v[2*MAXN];
     14 vector<int> query[2*MAXN];
     15 map<pair<int, int>, int> qid;
     16 string ans[MAXN];
     17 int color[2*MAXN];
     18 bool flag[MAXN];
     19 int n, m, cnt;
     20 vector<int> v1[MAXN];
     21 
     22 struct unionFindSet
     23 {
     24     int st[2*MAXN];
     25     void init()
     26     {
     27         for(int i=0; i<2*MAXN; ++i)   st[i] = i;
     28     }
     29     int findSet(int x)
     30     {
     31         if(x==st[x]) return x;
     32         return st[x] = findSet(st[x]);
     33     }
     34     void unionSet(int x, int y)
     35     {
     36         int sx = findSet(x), sy = findSet(y);
     37         st[sx] = sy;
     38     }
     39 }ufs;
     40 
     41 void init()
     42 {
     43     cnt = 0;
     44     for(int i=0; i<2*MAXN; ++i) v[i].clear();
     45     mp.clear();
     46     for(int i=0; i<2*MAXN; ++i) query[i].clear();
     47     qid.clear();
     48     memset(color, 0x11, sizeof(color));
     49     memset(flag, 0, sizeof(flag));
     50     for(int i=0; i<MAXN; ++i) v1[i].clear();
     51     ufs.init();
     52 }
     53 
     54 void handleRepetition(int x)
     55 {
     56     for(int i=0; i<v1[x].size(); ++i)
     57     {
     58         ans[v1[x][i]] = ans[x];
     59         handleRepetition(v1[x][i]);
     60     }
     61 }
     62 
     63 void solute(int x, int y)
     64 {
     65     if(flag[qid[pair<int, int>(x,y)]]) {}
     66     else if(color[y]==0)
     67     {
     68         ans[qid[pair<int, int>(x,y)]] = name[y];
     69         flag[qid[pair<int, int>(x,y)]] = true;
     70     }
     71     else if(color[y]==1)
     72     {
     73         ans[qid[pair<int, int>(x,y)]] = name[ufs.findSet(y)];
     74         flag[qid[pair<int, int>(x,y)]] = true;
     75     }
     76     if(color[y]>=0) handleRepetition(qid[pair<int, int>(x,y)]);
     77 }
     78 
     79 void tarjan(int x)
     80 {
     81     color[x] = 0;
     82     for(int i=0; i<v[x].size(); ++i)
     83     {
     84         tarjan(v[x][i]);
     85         ufs.unionSet(v[x][i], x);
     86     }
     87     for(int i=0; i<query[x].size(); ++i)    solute(x, query[x][i]);
     88     color[x] = 1;
     89 }
     90 
     91 int main()
     92 {
     93     string name1, name2;
     94     while(cin>>n)
     95     {
     96         init();
     97         while(n--)
     98         {
     99             cin>>name1>>name2;
    100             if(mp.find(name1)==mp.end())
    101             {
    102                 mp[name1] = cnt;
    103                 name[cnt++] = name1;
    104             }
    105             if(mp.find(name2)==mp.end())
    106             {
    107                 mp[name2] = cnt;
    108                 name[cnt++] = name2;
    109             }
    110             v[mp[name1]].push_back(mp[name2]);
    111         }
    112         cin>>m;
    113         int id = 0;
    114         while(m--)
    115         {
    116             cin>>name1>>name2;
    117             query[mp[name1]].push_back(mp[name2]);
    118             query[mp[name2]].push_back(mp[name1]);
    119             int tmp = -1;
    120             if(qid.find(pair<int, int>(mp[name1], mp[name2]))!=qid.end())
    121                 tmp = qid[pair<int, int>(mp[name1], mp[name2])];
    122             qid[pair<int, int>(mp[name1], mp[name2])] = id++;
    123             qid[pair<int, int>(mp[name2], mp[name1])] = id-1;
    124             if(tmp!=-1) v1[id-1].push_back(tmp);
    125         }
    126         tarjan(0);
    127         for(int i=0; i<id; ++i) cout<<ans[i]<<endl;
    128     }
    129 
    130     return 0;
    131 }

    题目链接:http://hihocoder.com/problemset/problem/1067

  • 相关阅读:
    三 面向对象之绑定方法与非绑定方法
    二 面向对象三大特性
    一 面向对象定义
    面向对象路线
    七 递归与二分法、匿名函数、内置函数
    线程同步测试
    Oracle12c的安装
    git教程:添加远程仓库
    git教程:远程仓库
    git教程:删除文件
  • 原文地址:https://www.cnblogs.com/pczhou/p/4296966.html
Copyright © 2011-2022 走看看