[HAOI2006]受欢迎的牛

题目描述:

众所周知,喜欢是可以传递的(bushi,给你N头牛,给你M对喜欢关系,如果A喜欢B,B喜欢C,则我们认为A也喜欢C,现在需要求有多少头牛被所有牛喜欢

思路:

还是先进行tarjan缩点,当且仅当存在一个出度为0的点集,则输出该点集的数量,否则输出0

为什么呢?缩点以后得到的个有向无环图,如果一个点出度不为0,则他必然是一条路径的中间位置,也就是他指向下一个点,而因为是无环,则下一个点是不会指向他的,所以他已经不符合所有人都喜欢他的条件了,再说为什么必须只有一个,因为如果存在多个,这些点的出度都为0,那这些点都没法到达别的点,这样就不会存在一个点会被所有人喜欢

此时悟出了人生哲理,当你表现出不想讨好任何人的时候,别人都会来讨好你(bushi

#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<string>
#include<vector>
#include<sstream>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define eps 1.0E-8
#define endl '\n'
//#define inf 0x3f3f3f3f
#define MAX  300000 + 50
#define mod 1000000007
#define lowbit(x) (x & (-x))
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d %d",&n,&m)
#define pd(n) printf("%d\n", (n))
#define pdd(n,m) printf("%d %d\n",n, m)
#define sddd(n,m,z) scanf("%d %d %d",&n,&m,&z)
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define mem(a,b) memset((a),(b),sizeof(a))
#define max(a,b) (((a)>(b)) ? (a):(b))
#define min(a,b) (((a)>(b)) ? (b):(a))
typedef  long long ll ;
typedef unsigned long long ull;
//不开longlong见祖宗!不看范围见祖宗!
inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

int n, m, x, y;

int tot;
int head[MAX];
struct ran{
    int to, nex;
}tr[MAX];
void add(int u, int v){
    tr[++tot].to = v;
    tr[tot].nex = head[u];
    head[u] = tot;
}

int tim;
int cnt;
int color[MAX];
int out[MAX];
int num[MAX];
stack<int>st;
int dfn[MAX], low[MAX];
bool vis[MAX];
void tarjan(int u){
    st.push(u);
    dfn[u] = low[u] = ++tim;
    vis[u] = 1;
    for(int i = head[u]; i; i = tr[i].nex){
        int v = tr[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if(vis[v])low[u] = min(low[u], dfn[v]);
    }
    if(dfn[u] == low[u]){
        int now;
        ++cnt;
        do {
            now = st.top();
            vis[now] = 0;
            st.pop();
            color[now] = cnt;
            ++num[cnt];
        } while (now != u);
    }
}


int main(){
    sdd(n, m);
    for(int i = 1; i <= m; ++i){
        sdd(x, y);
        add(x, y);
    }
    for(int i = 1; i <= n; ++i){
        if(!dfn[i])tarjan(i);
    }
    for(int i = 1; i <= n; ++i){
        for(int j = head[i]; j; j = tr[j].nex){
            int v = tr[j].to;
            if(color[i] != color[v]){
                ++out[color[i]];
            }
        }
    }

    int ans = 0;
    for(int i = 1; i <= cnt; ++i){
        if(!out[i])++ans;
    }
    if(ans == 1){
        for(int i = 1; i <= cnt; ++i){
            if(!out[i]){
                cout << num[i] << endl;
                break;
            }
        }
    }
    else cout << 0 << endl;
    return 0;
}