[ZJOI2007]最大半连通子图

Description

BZOJ1093

Luogu2272

Solution

强连通一定半联通,所以就缩一下点。然后DAG上DP一下最长链就可以了,注意边表去一下重防止计数出错。

Code

一开始不会去重,所以蒯了别人的去重方法,代码可能有点丑。

const int N = 100010;
const int M = 1000010;

struct Graph {
    int hd[N], to[M], nxt[M], cnt;
    void adde(int x, int y) {
        to[++cnt] = y;
        nxt[cnt] = hd[x];
        hd[x] = cnt;
    }
} G;

int n, m, ha, f[N], g[N];
int w[N], dfn[N], low[N], dft, sta[N], top, ins[N], bel[N], tot, deg[N], ind[N];
std::vector<int> DAG[N];
std::queue<int> Q;

void tarjan(int x) {
    ins[sta[++top] = x] = 1;
    dfn[x] = low[x] = ++dft;
    for (int i = G.hd[x]; i; i = G.nxt[i]) {
        int &v = G.to[i];
        if (!dfn[v]) {
            tarjan(v);
            low[x] = std::min(low[x], low[v]);
        } else if (ins[v])
            low[x] = std::min(low[x], dfn[v]);
    }
    if (dfn[x] == low[x]) {
        ++tot;
        int y;
        do {
            y = sta[top--];
            bel[y] = tot;
            ins[y] = 0;
            w[tot]++;
        } while (y != x);
    }
}

void main() {
    n = read(), m = read(), ha = read();
    for (int i = 1, x, y; i <= m; ++i) {
        x = read(), y = read();
        G.adde(x, y);
    }
    for (int i = 1; i <= n; ++i)
        if (!dfn[i]) tarjan(i);
    for (int i = 1; i <= n; ++i) {
        for (int j = G.hd[i]; j; j = G.nxt[j])
            if (bel[G.to[j]] != bel[i]) {
                DAG[bel[i]].push_back(bel[G.to[j]]);
            }
    }
    for (int i = 1; i <= tot; ++i) {
        std::sort(DAG[i].begin(), DAG[i].end());
        deg[i] = std::unique(DAG[i].begin(), DAG[i].end()) - DAG[i].begin();
        for (int j = 0; j < deg[i]; ++j) ind[DAG[i][j]]++;
        f[i] = w[i];
        g[i] = 1;
    }
    for (int i = 1; i <= tot; ++i)
        if (!ind[i]) Q.push(i);
    while (!Q.empty()) {
        int x = Q.front();
        Q.pop();
        for (int i = 0; i < deg[x]; ++i) {
            int &y = DAG[x][i];
            if (f[x] + w[y] > f[y])
                f[y] = f[x] + w[y], g[y] = g[x];
            else if (f[x] + w[y] == f[y])
                g[y] = (g[y] + g[x]) % ha;
            if (--ind[y] == 0) Q.push(y);
        }
    }
    int ans1 = 0, ans2 = 0;
    for (int i = 1; i <= tot; ++i)
        if (f[i] > ans1) {
            ans1 = f[i];
            ans2 = g[i];
        } else if (f[i] == ans1) {
            ans2 = (ans2 + g[i]) % ha;
        }
    printf("%d %d\n", ans1, ans2);
}
posted @ 2018-10-30 12:28  wyxwyx  阅读(122)  评论(0编辑  收藏  举报