hdu 4695 Important Sisters

支配树模版题~

这东西似乎非常好写……

但是证明好长好长啊~

$$sdom(u) = min\{\{v|(v, u) \in E, dfn(v) < dfn(u)\}\cup\{sdom(q)|dfn(q)>dfn(u), \exists  (p, x) \in E, q \in path(S, p)\}\}$$

前一半是走前向边或者树边,后一半是走横叉边或者返祖边

$$idom(u) = \begin{cases}sdom(u)& \text{ if } sdom(v)= sdom(u)\\ idom(v) & \text{ if } sdom(v)<sdom(u) \end{cases}$$

其中\(v\)代表\((sdom(u), u]\)之中\(sdom\)最小的那一个点。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 200000;
int n, m;
int dfn[N], lst[N], id[N], sd[N], paid[N], mns[N];
int anc[N], par[N], tot;
vector <int> bi[N], bp[N], bb[N];
LL sum[N];
void dfs(int t)
{
    dfn[t] = ++ tot; lst[tot] = t;
    for (int i = 0; i < bi[t].size(); ++ i)
        if (!dfn[bi[t][i]])
            dfs(bi[t][i]), par[bi[t][i]] = t;
}
int check_min(int a, int b)
{
    if (dfn[a] < dfn[b]) return a; else return b;
}
int find_anc(int t)
{
    if (anc[t] == t) return t;
    else
    {
        int a = find_anc(anc[t]);
        if (a != anc[t] && dfn[sd[mns[anc[t]]]] < dfn[sd[mns[t]]])
            mns[t] = mns[anc[t]];
        return anc[t] = a;
    }
}
int main()
{
    while (scanf("%d%d", &n, &m) == 2)
    {
        for (int i = 0; i <= n; ++ i)
            bi[i].clear(), bp[i].clear(), bb[i].clear();
        for (int i = 0; i <= n; ++ i)
            dfn[i] = lst[i] = par[i] = id[i] = sd[i] = paid[i] = sum[i] = 0;
        for (int i = 1; i <= n; ++ i) anc[i] = mns[i] = i;
        tot = 0;
        for (int i = 1; i <= m; ++ i)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            bi[a].push_back(b);
            bp[b].push_back(a);
        }
        dfs(n);
        for (int i = n; ; -- i)
        {
            for (int j = 0; j < bb[lst[i]].size(); ++ j)
            {
                find_anc(bb[lst[i]][j]);
                if (sd[mns[bb[lst[i]][j]]] == sd[bb[lst[i]][j]])
                    id[bb[lst[i]][j]] = sd[bb[lst[i]][j]];
                else
                    paid[bb[lst[i]][j]] = mns[bb[lst[i]][j]];
            }
            if (i == 1) break;
            sd[lst[i]] = par[lst[i]];
            for (int j = 0; j < bp[lst[i]].size(); ++ j) if (dfn[bp[lst[i]][j]])
            {
                if (dfn[bp[lst[i]][j]] < i)
                    sd[lst[i]] = check_min(sd[lst[i]], bp[lst[i]][j]);
                else
                {
                    find_anc(bp[lst[i]][j]);
                    sd[lst[i]] = check_min(sd[lst[i]], sd[mns[bp[lst[i]][j]]]);
                }
            }
            mns[lst[i]] = lst[i];
            anc[lst[i]] = par[lst[i]];
            bb[sd[lst[i]]].push_back(lst[i]);
        }
        for (int i = 1; i <= n; ++ i) if (paid[lst[i]])
            id[lst[i]] = id[paid[lst[i]]];
        // for (int i = 1; i <= n; ++ i)
            // printf("%d\n", id[i]);
        for (int i = 1; i <= n; ++ i)
            sum[lst[i]] = sum[id[lst[i]]] + lst[i];
        for (int i = 1; i <= n; ++ i)
            printf("%lld%c", sum[i], (i == n? '\n': ' '));
    }
}

 

posted @ 2017-12-24 21:33 AwD! 阅读(...) 评论(...) 编辑 收藏