CF505D Mr. Kitayuta's Technology

CF505D Mr. Kitayuta's Technology

一道结论题。

(M) 个询问中提及的点数为 (cnt), 记这些点按照询问形成图的联通块个数为 (K),第 (i) 个联通块大小为 (siz_i)

对于每个联通块,容易发现边数不是 (siz_i-1) 就是 (siz_i) 那么什么时候是(siz_i-1) 呢,是这个联通块不含强连通分量的时候。反之为 (siz_i),这个可以手动验证。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>

using namespace std;

typedef int ll;
const ll MAXN = 1e6+10;

stack <ll> st;
vector <ll> g[MAXN], g2[MAXN];
ll N, M, fa[MAXN], siz[MAXN], has[MAXN], num, dfn[MAXN], low[MAXN], vis[MAXN];
ll bel[MAXN], _N, tag1[MAXN], tag2[MAXN];

ll find_(ll);
void tarjan(ll);

int main() {
    scanf("%d%d", &N, &M);
    for (ll i = 1, x, y; i <= M; i++) {
        scanf("%d%d", &x, &y);
        tag1[x] = tag1[y] = 1;
        g[x].push_back(y);
    }
    for (ll i = 1; i <= N; i++) if (!dfn[i]) tarjan(i);
    for (ll i = 1; i <= N; i++) {
        for (unsigned int j = 0; j < g[i].size(); j++) {
            ll v = g[i][j];
            if (bel[v] != bel[i]) g2[bel[i]].push_back(bel[v]);
            else has[bel[i]] = 1;
        }
        if (tag1[i]) tag2[bel[i]] = 1;
    }
    for (ll i = 1; i <= _N; i++)
        sort(g2[i].begin(), g2[i].end()), g2[i].erase(unique(g2[i].begin(), g2[i].end()), g2[i].end());
    for (ll i = 1; i <= _N; i++) fa[i] = i;
    for (ll i = 1; i <= _N; i++) {
        for (unsigned int j = 0; j < g2[i].size(); j++) {
            ll fx = find_(i), fy = find_(g2[i][j]);
            if (fx != fy) {
                fa[fx] = fy;
                has[fy] |= has[fx];
                siz[fy] += siz[fx];
            }
        }
    }
    ll ans = 0;
    for (ll i = 1; i <= _N; i++) {
        if (find_(i) == i && tag2[i]) {
            ans += siz[i] - 1 + has[i];
        }
    }
    printf("%d
", ans);
    return 0;
}

void tarjan(ll n) {
    dfn[n] = low[n] = ++num;
    st.push(n);
    for (unsigned int i = 0; i < g[n].size(); i++) {
        ll v = g[n][i];
        if (vis[v]) continue;
        if (dfn[v]) low[n] = min(low[n], dfn[v]);
        else {
            tarjan(v);
            low[n] = min(low[n], low[v]);
        }
    }
    if (dfn[n] == low[n]) {
        ll t;
        _N++;
        do {
            t = st.top();
            st.pop();
            bel[t] = _N;
            vis[t] = 1;
            siz[_N] += tag1[t];
        } while (n != t);
    }
}

ll find_(ll x) {return fa[x] == x ? x : fa[x] = find_(fa[x]);}
原文地址:https://www.cnblogs.com/Gensokyo-Alice/p/13904529.html