强联通缩点拓扑排序去重边小技巧

拓扑排序时设当前队首为u,对u->v,将访问过的v节点的vis设为u,这样就可以判断这条边是否重复

例:OJ 1566

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

inline long long read(){
    long long ans = 0, f = 1;
    char ch = getchar();
    while(!isdigit(ch))
        f *= (ch == -) ? -1 : 1, ch = getchar();
    do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar();
    while(isdigit(ch));
    return ans * f;
}

const int MAXN = 100005, MAXM = 1000005;
struct Graph{
    int head[MAXN], last[MAXM], next[MAXM], lineNum;
    void add(int x,int y){
        lineNum++, next[lineNum] = head[x], last[lineNum] = y, head[x] = lineNum;
    }    
}G, G2;

int dfn[MAXN], low[MAXN], vis[MAXN], siz[MAXN], bel[MAXN], sta[MAXN], inch[MAXN], cnt = 0;
int Dp[MAXN], dep[MAXN];
queue<int> Q;
void tarjan(int x){
    dfn[x] = low[x] = ++dfn[0], sta[++sta[0]] = x, vis[x] = true;
    for(int l=G.head[x]; l; l=G.next[l]){
        int y = G.last[l];
        if(!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]);
        else if(vis[y]) low[x] = min(low[x], dfn[y]);
    }
    if(low[x] == dfn[x]){
        cnt++;
        do bel[sta[sta[0]]] = cnt, vis[sta[sta[0]]] = false, siz[cnt]++;
        while(sta[sta[0]--] != x);
    }
}

int main(){
    int N = read(), M = read(), MOD = read();
    for(int i=1; i<=M; i++){
        int u = read(), v = read();
        G.add(u, v);
    }
    for(int i=1; i<=N; i++) if(!dfn[i])
        tarjan(i);
    for(int x=1; x<=N; x++) for(int l=G.head[x]; l; l=G.next[l]){
        int y = G.last[l];
        if(bel[x] != bel[y])
            G2.add(bel[x], bel[y]), inch[bel[y]]++;
    }
    for(int i=1; i<=cnt; i++) if(!inch[i])
        Q.push(i), dep[i] = siz[i], Dp[i] = 1;
    memset(vis, 0, sizeof(vis));
    while(!Q.empty()){
        int x = Q.front();
        Q.pop();
        for(int l=G2.head[x]; l; l=G2.next[l]){
            int y = G2.last[l];
            inch[y]--;
            if(!inch[y]) Q.push(y);
            if(vis[y] == x) continue;
            vis[y] = x;
            if(dep[y] < dep[x] + siz[y])
                dep[y] = dep[x] + siz[y], Dp[y] = Dp[x];
            else if(dep[y] == dep[x] + siz[y])
                Dp[y] = (Dp[y] + Dp[x]) % MOD;
        }
    }
    int ans = 0, maxDep = 0;
    for(int i=1; i<=cnt; i++){
        if(maxDep < dep[i])
            maxDep = dep[i], ans = Dp[i];
        else if(maxDep == dep[i])
            ans = (ans + Dp[i]) % MOD;
    }
    printf("%d\n%d", maxDep, ans);
    return 0;
}

 

强联通缩点拓扑排序去重边小技巧

上一篇:原来iPhone手机这么好用!点2下屏幕就能长截屏,实用又方便


下一篇:application designer中修改属性秒退的问题