其他分享
首页 > 其他分享> > 支配树简记(不是教程)

支配树简记(不是教程)

作者:互联网

Pre

看了两天,终于看懂了(比\(\frac{1}{\infty}\)高阶的无穷小)\(\%\)。

Hints

1、初始化的三个数组要记住\(val.f.sdom\)。

2、\(find\)函数有一点神奇,之前没有见过,可以熟悉一下。

3、\(69\)~\(71\)行的代码,就是更新\(sdom\)的那一部分,考虑转移到\(sdom(x)\)。

当\(dfn(y)<dfn(x)\)

\(y\)还没有被访问并更新答案,因为我们是按照从大到小的顺序操作的,所以\(sdom(x)=y\)。

当\(dfn(y)>dfn(x)\)

\(y\)已经被更新,但是\(y\)的第二浅的老祖宗的\(dfn\)不会小于\(x\),最浅的老祖宗可以作为\(sdom(x)\)因为满足之间的点的\(dfn\)大于\(dfn(x)\),所以可以转移。

4、注意\(73\)行转移到\(tree\)的图里面。

5、\(83\)行,这是一个神奇的东西。因为\(idom(st.val(v))\)在这个时候时可能没有初始化的,为\(0\),又不能够在程序开始初始化,所以只有最后处理完了再来处理这个地方。

(开始的时候我以为我少考虑了几种情况,结果浪费了\(1\)个小时找推理错误,发现没有错)。

6、最重要的,大致思路要知道。

下面的代码是洛谷的模板题的。

Code

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define xx first
#define yy second
 
using namespace std;

const int N = 200000 + 5, M = 300000 + 5;

int n, m, fa[N], sdom[N], idom[N], dfn[N], id[N], cnt, ans[N];

struct Graph {
    int fr[M << 1], to[M << 1], h[N], tot;
    void cal (int u) {
        ans[u] = 1;
        for (int i = h[u]; i; i = fr[i]) {
            cal (to[i]);
            ans[u] += ans[to[i]];
        }
    }
    inline void add (int u, int v) {
        ++tot;
        fr[tot] = h[u];
        to[tot] = v;
        h[u] = tot;
    }
    void dfs (int u) {
        dfn[u] = ++cnt;
        id[cnt] = u;
        for (int i = h[u]; i; i = fr[i]) {
            if (!dfn[to[i]]) {
                dfs (to[i]);
                fa[to[i]] = u;
            }
        }
    }
}pos, neg, tree, Ans;

struct UnionSet {
    int f[N], val[N];
    inline void init (int n = N - 5) {
        for (int i = 1; i <= n; ++i) {
            f[i] = i;
            val[i] = i;
            sdom[i] = i;
        }
    }
    inline void find (int u) {
        if (f[u] == u) {
            return ;
        }
        find (f[u]);
        int rt = f[f[u]];
        if (dfn[sdom[val[f[u]]]] < dfn[sdom[val[u]]]) {
            val[u] = val[f[u]];
        }
        f[u] = rt;
    }
}st;

inline void LT () {
    st.init(n);
    for (int i = cnt; i >= 2; --i) {
        int now = id[i];
        for (int j = neg.h[now]; j; j = neg.fr[j]) {
            int v = neg.to[j];
            st.find (v);
            if (dfn[sdom[now]] > dfn[sdom[st.val[v]]]) {
                sdom[now] = sdom[st.val[v]];
            }
        }
        tree.add(sdom[now], now);
        st.f[now] = fa[now];
        now = fa[now];
        for (int j =tree.h[now]; j; j = tree.fr[j]) {
            int v = tree.to[j];
            st.find(v);
            if (sdom[st.val[v]] == now) {
                idom[v] = now;
            }
            else {
                idom[v] = st.val[v];
            }
        }
    }
    for (int i = 1; i <= n; ++i) {
        int now = id[i];
        if (sdom[now] != idom[now]) {
            idom[now] = idom[idom[now]];
        }
    }
}

int main () {
    scanf ("%d%d", &n, &m);
    for (int i = 1; i <= m; ++i) {
        int x, y;
        scanf ("%d%d", &x, &y);
        pos.add (x, y);
        neg.add (y, x);
    }
    pos.dfs (1);
    LT ();
    for (int i = 1; i <= n; ++i) {
        if (idom[i]) {
            Ans.add(idom[i], i);
        }
    }
    Ans.cal (1);
    for (int i = 1; i <= n; ++i) {
        printf ("%d ", ans[i]);
    }
    return 0;
}

Concluion

大概就这样。

两天的时间打出了我的支配树代码,接下来想花一些时间做一些相关的题目,熟悉一下。

话说这和Conclusion有什么关系

标签:sdom,教程,val,int,支配,st,简记,dfn,now
来源: https://www.cnblogs.com/ChiTongZ/p/11178633.html