HDU 4694: Important Sisters(支配树) 存个板子

推荐资料:

Lengauer-Tarjan算法--支配树构造

知乎详解

最详细的证明

题目连接:

hdu 4694 Important Sisters

题意:固定起点n,定义每个点 i 的答案是:从n到 i 路径上所有的点 j, 如果删除 j 之后 n 走不到 i,那么ans[i] += j,求出每个点的答案。

魔改网上的板子:

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int maxn = 5e4 + 10;
vector<int> pre[maxn], dom[maxn], G[maxn];
int n, m, semi[maxn], idom[maxn], tot;
int id[maxn], dfn[maxn], fa[maxn], father[maxn], val[maxn];
void dfs(int x) {
    dfn[x] = ++tot;
    id[tot] = x;
    for (auto v : G[x]) {
        pre[v].pb(x);
        if (!dfn[v]) {
            fa[v] = x;
            dfs(v);
        }
    }
}
int get(int x) {
    if (father[x] == x)
        return x;
    int y = get(father[x]);
    if (dfn[semi[val[father[x]]]] < dfn[semi[val[x]]])
        val[x] = val[father[x]];
    return father[x] = y;
}
int smin(int x,int y) {return dfn[x] < dfn[y] ? x : y; }
void solve() {
    for (int i = tot; i >= 2; i--) {
        int u = id[i];
        for (auto v : pre[u])
            if (dfn[v] < dfn[u])
                semi[u] = smin(semi[u], v);
            else {
                get(v);
                semi[u] = smin(semi[u], semi[val[v]]);
            }
        father[u] = fa[u];
        dom[semi[u]].pb(u);
        for (auto v : dom[fa[u]]) {
            get(v);
            int x = val[v];
            idom[v] = (dfn[semi[x]] < dfn[semi[v]]) ? x : fa[u];
        }
    }
    for (int i = 2; i <= tot; i++) {
        int x = id[i];
        if (idom[x] != semi[x])
            idom[x] = idom[idom[x]];
    }
}
ll ans[maxn];
void calc() {
    for (int i = 1; i <= n; i++)
        ans[i] = 0;
    for (int i = 1; i <= tot; i++) {
        int x = id[i];
        ans[x] += x;
        if (idom[x])
            ans[x] += ans[idom[x]];
    }
}
int main() {
    int u, v;
    while (~scanf("%d%d", &n, &m)) {
        tot = 0;
        for (int i = 1; i <= n; i++) {
            pre[i].clear(), dom[i].clear(), G[i].clear();
            dfn[i] = idom[i] = 0;
            father[i] = val[i] = semi[i] = i;
        }
        for (int i = 1; i <= m; i++) {
            scanf("%d%d", &u, &v);
            G[u].pb(v);
        }
        dfs(n);
        solve();
        calc();
        for (int i = 1; i <= n; i++)
            printf("%lld%c", ans[i], (i == n) ? '\n' : ' ');
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值