luogu P2272 [ZJOI2007]最大半连通子图

我们可以发现 一个强联通分量内的点是可以任意到达的

我们不妨把它缩成一个点 这样子就成了一个 DAG D A G
当然这个时候也不要忘了判断缩点后的重边

直接dp搞一下就好了

#include

#define pb push_back

using namespace std;

const int N = 1e5 + 10; 

vector<int> G1[N], G2[N], kuai[N];
int n, m, mod, be[N], color, size[N];
int de[N], f[N], cnt[N];
map<int, int> G[N];

namespace Tarjan {
    int low[N], dfn[N], Sta[N], cnt, top, ins[N];
    void dfs(int x) {
        dfn[x] = low[x] = ++ cnt; Sta[++ top] = x; ins[x] = size[x] = 1;
        for(int j = 0, sz = G1[x].size(); j < sz; ++ j) {
            if(!dfn[G1[x][j]]) {
                dfs(G1[x][j]);
                low[x] = min(low[x], low[G1[x][j]]);
            }
            else if(ins[G1[x][j]])
                low[x] = min(low[x], dfn[G1[x][j]]);
        }
        if(low[x] == dfn[x]) {
            ++ color;
            do {
                kuai[color].pb(Sta[top]);
                ins[Sta[top]] = 0;
                be[Sta[top]] = color;
            }while(x != Sta[top --]);
        }
    }

    void New_Graph() {
        for(int i = 1; i <= color; ++ i) {
            size[i] = kuai[i].size();
            for(auto u : kuai[i])
                for(auto v : G1[u])
                    if(be[u] != be[v] && !G[be[u]][be[v]]) 
                        G2[be[u]].pb(be[v]), ++ de[be[v]], G[be[u]][be[v]] = 1;
        }
    }
}

void Topsort() {
    queue<int> q;
    for(int i = 1; i <= color; ++ i)
        if(!de[i]) {
            q.push(i); f[i] = size[i]; cnt[i] = 1;
        }
    while(!q.empty()) {
        int k = q.front(); q.pop();
        for(auto v : G2[k]) { 
            if(!(-- de[v])) q.push(v);
            if(f[v] < f[k] + size[v]) {
                f[v] = f[k] + size[v];  
                cnt[v] = 0;
            }
            if(f[v] == f[k] + size[v]) 
                (cnt[v] += cnt[k]) %= mod;
        }
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("2272.in", "r", stdin);
    freopen("2272.out", "w", stdout);
#endif
    int x, y, ans1 = 0, ans2;
    scanf("%d%d%d", &n, &m, &mod);
    for(int i = 1; i <= m; ++ i) {
        scanf("%d%d", &x, &y);
        G1[x].pb(y);
    }
    for(int i = 1; i <= n; ++ i) 
        if(!Tarjan::dfn[i])
            Tarjan::dfs(i);
    Tarjan::New_Graph();
    Topsort();
    for(int i = 1; i <= color; ++ i) {
        if(f[i] > ans1) 
            ans1 = f[i], ans2 = 0;
        if(f[i] == ans1)
            (ans2 += cnt[i]) %= mod;
    }
    printf("%d\n%d", ans1, ans2);
    return 0;
}

你可能感兴趣的:(luogu P2272 [ZJOI2007]最大半连通子图)