zoukankan      html  css  js  c++  java
  • Dominator Tree & Lengauer-Tarjan Algorithm

    问题描述

    给出一张有向图,可能存在环,对于所有的i,求出从1号点到i点的所有路径上的必经点集合。

    什么是支配树

    两个简单的小性质——

    1.如果i是j的必经点,而j又是k的必经点,则i也是k的必经点。

    2.如果i和j都是k的必经点,则i和j之间必然存在必经点关系,不可能互相都不是必经点。

    不难发现所有的必经点关系形成了一个以1点为根的树形关系,每个点的支配点集合就是其到根节点(1点)路径上的点集,称这棵树为支配树。

    怎么求支配树

    假如我们得到的是一个有向无环图,那么只需要$O(N)$的做一遍拓扑排序就可以了,非常简单。

    假如我们得到了一张有向有环图,那么我们可以$O(N)$的枚举一个点,把它从图上删去,从根$O(M)$的DFS(或BFS)一次,就可以知道它是哪些点的必经点,复杂度$O(NM)$,简单粗暴,但时间复杂度难以接受。

    然后就有了Lengauer-Tarjan算法,复杂度为$O(NlogN)$,有一堆定理证明,想详细的搞明白最好去看Tarjan的英文论文,网上有些中文翻译难免带些小错误。

    简单的上手题

    据某位大佬说,这个算法还没见到过不是裸题的题…… OTZ

    不过确实,目前这个算法一般应用在浅层,题面也是非常的裸,简直就是再说“快来拿支配树上我啊!”

    CodeChef Counting on a directed graph GRAPHCNT

      1 #include <bits/stdc++.h>
      2  
      3 using namespace std;
      4  
      5 typedef long long lnt;
      6  
      7 const int mxn = 100005;
      8  
      9 int n, m;
     10  
     11 int tim;
     12 int dfn[mxn];
     13 int idx[mxn];
     14 int fat[mxn];
     15 int idm[mxn];
     16 int sdm[mxn];
     17 int anc[mxn];
     18 int tag[mxn];
     19 lnt siz[mxn];
     20 lnt son[mxn];
     21  
     22 vector<int> G[mxn];
     23 vector<int> R[mxn];
     24 vector<int> S[mxn];
     25 vector<int> T[mxn];
     26  
     27 void dfsG(int u)
     28 {
     29     idx[dfn[u] = ++tim] = u;
     30     
     31     for (auto v : G[u])if (!dfn[v])
     32         fat[v] = u, dfsG(v);
     33 }
     34  
     35 void dfsT(int u)
     36 {
     37     siz[u] = 1;
     38     
     39     for (auto v : T[u])
     40         dfsT(v), siz[u] += siz[v];
     41 }
     42  
     43 int find(int u)
     44 {
     45     if (u == anc[u])
     46         return u;
     47     
     48     int r = find(anc[u]);
     49     
     50     if (dfn[sdm[tag[anc[u]]]] < dfn[sdm[tag[u]]])
     51         tag[u] = tag[anc[u]];
     52     
     53     return anc[u] = r;
     54 }
     55  
     56 signed main(void) 
     57 {
     58     cin >> n >> m;
     59     
     60     for (int i = 1, u, v; i <= m; ++i)
     61     {
     62         cin >> u >> v;
     63         G[u].push_back(v);
     64         R[v].push_back(u);
     65     }
     66     
     67     for (int i = 1; i <= n; ++i)
     68         sdm[i] = tag[i] = anc[i] = i;
     69     
     70     dfsG(1);
     71     
     72     for (int i = tim; i > 1; --i)
     73     {
     74         int u = idx[i];
     75         
     76         for (auto v : R[u])if (dfn[v])
     77         {
     78             find(v);
     79             if (dfn[sdm[tag[v]]] < dfn[sdm[u]])
     80                 sdm[u] = sdm[tag[v]];
     81         }
     82         
     83         anc[u] = fat[u];
     84         
     85         S[sdm[u]].push_back(u);
     86         
     87         int t = idx[i - 1];
     88         
     89         for (auto v : S[t])
     90         {
     91             find(v);
     92             if (sdm[tag[v]] == t)
     93                 idm[v] = t;
     94             else
     95                 idm[v] = tag[v];
     96         }
     97         
     98         S[t].clear();
     99     }
    100     
    101     for (int i = 2; i <= tim; ++i)
    102     {
    103         int u = idx[i];
    104         if (idm[u] != sdm[u])
    105             idm[u] = idm[idm[u]];
    106     }
    107     
    108     for (int i = 2; i <= tim; ++i)
    109         T[idm[i]].push_back(i);
    110     
    111     dfsT(1);
    112     
    113     lnt ans = tim * (tim - 1);
    114     
    115     for (int i = tim, u; i >= 2; --i)
    116     {
    117         ++son[u = idx[i]];
    118         if (idm[u] != 1)
    119             son[idm[u]] += son[u];
    120         else
    121             ans -= son[u] * (son[u] - 1);
    122     }
    123     
    124     ans >>= 1;
    125     
    126     cout << ans << endl;
    127 } 
    View Code

    HDU 4694 Important Sisters

      1 #include <cstdio>
      2 #include <cstring>
      3 
      4 #define mxn 50005
      5 #define mxm 200005
      6 #define lnt long long
      7 
      8 int n, m;
      9 
     10 struct Lin {
     11     int tt;
     12     int hd[mxn];
     13     int nt[mxm];
     14     int to[mxm];
     15     
     16     void init(void) {
     17         memset(hd, 0, sizeof hd), tt = 0;
     18     }
     19     
     20     void adde(int u, int v) {
     21         nt[++tt] = hd[u], to[tt] = v, hd[u] = tt;
     22     }
     23 }G, R, T, S;
     24 
     25 int tim;
     26 int idx[mxn];
     27 int dfn[mxn];
     28 int fat[mxn];
     29 int anc[mxn];
     30 int tag[mxn];
     31 int sdm[mxn];
     32 int idm[mxn];
     33 lnt ans[mxn];
     34 
     35 void dfsG(int u) {
     36     idx[dfn[u] = ++tim] = u;
     37     
     38     for (int i = G.hd[u], v; i; i = G.nt[i])
     39         if (!dfn[v = G.to[i]])dfsG(v), fat[v] = u;
     40 }
     41 
     42 void dfsT(int u) {
     43     ans[u] += u;
     44     
     45     for (int i = T.hd[u], v; i; i = T.nt[i])
     46         ans[v = T.to[i]] += ans[u], dfsT(v);
     47 }
     48 
     49 int find(int u) {
     50     if (anc[u] == u)return u;
     51     
     52     int r = find(anc[u]);
     53     
     54     if (dfn[sdm[tag[anc[u]]]] < dfn[sdm[tag[u]]])
     55         tag[u] = tag[anc[u]];
     56         
     57     return anc[u] = r;
     58 }
     59 
     60 signed main(void) 
     61 {
     62     while (scanf("%d%d", &n, &m) != EOF) {
     63         memset(ans, 0, sizeof ans);
     64         memset(dfn, 0, sizeof dfn), tim = 0;
     65         
     66         G.init(); R.init(); T.init(); S.init();
     67         
     68         for (int i = 1, u, v; i <= m; ++i)
     69             scanf("%d%d", &u, &v), G.adde(u, v), R.adde(v, u);
     70             
     71         for (int i = 1; i <= n; ++i)
     72             sdm[i] = tag[i] = anc[i] = i;
     73         
     74         dfsG(n);
     75         
     76         for (int i = tim; i > 1; --i) {
     77             int u = idx[i], v;
     78             
     79             for (int j = R.hd[u]; j; j = R.nt[j])
     80                 if (dfn[v = R.to[j]]) {
     81                     find(v);
     82                     if (dfn[sdm[tag[v]]] < dfn[sdm[u]])
     83                         sdm[u] = sdm[tag[v]];
     84                 }
     85                 
     86             anc[u] = fat[u]; S.adde(sdm[u], u); u = idx[i - 1];
     87             
     88             for (int j = S.hd[u]; j; j = S.nt[j]) {
     89                 find(v = S.to[j]);
     90                 if (sdm[tag[v]] == u)
     91                     idm[v] = u;
     92                 else
     93                     idm[v] = tag[v];
     94             }
     95         }
     96         
     97         for (int i = 2; i <= tim; ++i) {
     98             int u = idx[i];
     99             if (idm[u] != sdm[u])
    100                 idm[u] = idm[idm[u]];
    101             T.adde(idm[u], u);
    102         }
    103         
    104         dfsT(n);
    105         
    106         for (int i = 1; i < n; ++i)
    107             printf("%lld ", ans[i]);
    108             
    109         printf("%lld
    ", ans[n]);
    110     }
    111 }
    View Code

    SPOJ BIA - Bytelandian Information Agency

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 const int mxn = 5005;
      6 const int mxm = 200005;
      7 
      8 int n, m;
      9 
     10 vector<int> G[mxn];
     11 vector<int> R[mxn];
     12 vector<int> S[mxn];
     13 
     14 inline void init(vector<int> v[mxn])
     15 {
     16     for (int i = 0; i < mxn; ++i)
     17         v[i].clear();
     18 }
     19 
     20 int tim;
     21 int dfn[mxn];
     22 int idx[mxn];
     23 int fat[mxn];
     24 int idm[mxn];
     25 int sdm[mxn];
     26 int anc[mxn];
     27 int cnt[mxn];
     28 int tag[mxn];
     29 
     30 void dfsG(int u)
     31 {
     32     idx[dfn[u] = ++tim] = u;
     33     
     34     for (auto v : G[u])if (!dfn[v])
     35         fat[v] = u, dfsG(v);
     36 }
     37 
     38 int find(int u)
     39 {
     40     if (anc[u] == u)
     41         return u;
     42     
     43     int r = find(anc[u]);
     44     
     45     if (dfn[sdm[tag[anc[u]]]] < dfn[sdm[tag[u]]])
     46         tag[u] = tag[anc[u]];
     47     
     48     return anc[u] = r;
     49 }
     50 
     51 signed main(void) 
     52 {
     53     while (cin >> n >> m)
     54     {
     55         init(G);
     56         init(R);
     57         init(S);
     58         
     59         tim = 0;
     60         
     61         memset(cnt, 0, sizeof cnt);
     62         memset(dfn, 0, sizeof dfn);
     63         
     64         for (int i = 1, u, v; i <= m; ++i)
     65         {
     66             cin >> u >> v;
     67             G[u].push_back(v);
     68             R[v].push_back(u);
     69         }
     70         
     71         for (int i = 1; i <= n; ++i)
     72             sdm[i] = tag[i] = anc[i] = i;
     73         
     74         dfsG(1);
     75         
     76         for (int i = tim; i > 1; --i)
     77         {
     78             int u = idx[i];
     79             
     80             for (auto v : R[u])if (dfn[v])
     81             {
     82                 find(v);
     83                 if (dfn[sdm[tag[v]]] < dfn[sdm[u]])
     84                     sdm[u] = sdm[tag[v]];
     85             }
     86             
     87             anc[u] = fat[u];
     88             
     89             S[sdm[u]].push_back(u);
     90             
     91             u = idx[i - 1];
     92             
     93             for (auto v : S[u])
     94             {
     95                 find(v);
     96                 
     97                 if (sdm[tag[v]] == u)
     98                     idm[v] = u;
     99                 else
    100                     idm[v] = tag[v];
    101             }
    102             
    103             S[u].clear();
    104         }
    105         
    106         for (int i = 2; i <= tim; ++i)
    107         {
    108             int u = idx[i];
    109             if (idm[u] != sdm[u])
    110                 idm[u] = idm[idm[u]];
    111         }
    112         
    113         for (int i = 2; i <= tim; ++i)
    114             ++cnt[idm[i]];
    115             
    116         int ans = 0;
    117         
    118         for (int i = 1; i <= tim; ++i)
    119             if (cnt[i])++ans;
    120         
    121         cout << ans << endl;
    122         
    123         for (int i = 1; i <= tim; ++i)
    124             if (cnt[i])cout << i << " ";
    125         
    126         cout << endl; 
    127     }
    128 }
    View Code

    Useful Roads

    @Author: YouSiki

     

  • 相关阅读:
    Codeforces Round #634 E2. Three Blocks Palindrome (hard version)(双指针/前缀和/二分/好题)
    Codeforces Round #634 D. Anti-Sudoku(构造/水)
    自动化----docker
    自动化---zabbbix监控
    awk使用
    自动化-KVM安装
    nginx教程以及正则
    自动化-cobbler
    Python
    自动化kickstart
  • 原文地址:https://www.cnblogs.com/yousiki/p/6528785.html
Copyright © 2011-2022 走看看