【BZOJ】1051: [HAOI2006]受欢迎的牛(tarjan)

http://www.lydsy.com/JudgeOnline/problem.php?id=1051

这题还好~1A了。。但是前提还是看了题解的 囧。。。。。一开始认为是并查集,oh,不行,,无法维护和判断。。好吧。

看了题解后发现这是如何巧妙0v0!,我们将题目抽象为图,然后找出所有的环,你想啊,,,所有的换最后都有一条路径连向某一个环~那么恭喜这个环成为所有人的喜爱~~咳咳。。懂了吧。。判断这个最后的环用tarjan缩点后判断是否有且只有一个环没有连边出去,即出度为0,用前向星的就很好判断~~

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define read(a) a=getnum()
#define print(a) printf("%d", a)
inline int getnum() { int ret=0; char c; for(c=getchar(); c<'0' || c>'9'; c=getchar()); for(; c>='0' && c<='9'; c=getchar()) ret=ret*10+c-'0'; return ret; }

const int N=10005, M=50005;
int ihead[N], inext[M], to[M], cnt;
int LL[N], FF[N], top, s[N], p[N], cyc, tot, vis[N], hav[N];
int p_ihead[N], p_inext[M], p_cnt;
int n, m, ans;

inline void add(const int &u, const int &v) {
	inext[++cnt]=ihead[u]; ihead[u]=cnt; to[cnt]=v;
}

void dfs(int u) {
	s[++top]=u;
	vis[u]=1;
	LL[u]=FF[u]=++tot;
	for(int i=ihead[u]; i; i=inext[i]) {
		if(!FF[to[i]]) {
			dfs(to[i]);
			LL[u]=min(LL[u], LL[to[i]]);
		}
		else if(vis[to[i]] && FF[to[i]]<LL[u])
			LL[u]=FF[to[i]];
	}
	if(LL[u]==FF[u]) {
		++cyc;
		int r;
		do {
			r=s[top--];
			p[r]=cyc;
			vis[r]=0;
			++hav[cyc];
		} while(r!=u);
	}
}

void rebuild() {
	for1(u, 1, n) {
		for(int i=ihead[u]; i; i=inext[i]) {
			if(p[u] != p[to[i]]) {
				p_inext[++p_cnt]=p_ihead[p[u]];
				p_ihead[p[u]]=p_cnt;
			}
		}
	}
}

void tarjan() {
	for1(i, 1, n) if(!FF[i]) dfs(i);
	rebuild();
}

void getans() {
	for1(i, 1, cyc) if(!p_ihead[i]) {
		if(ans) { ans=0; return; }
		else ans=hav[i];
	}
}

int main() {
	int x, y;
	read(n); read(m);
	for1(i, 0, n+1) p[i]=i;
	rep(i, m) {
		read(x); read(y);
		add(x, y);
	}
	tarjan();
	getans();
	print(ans);
	return 0;
}

 

 


 

 

Description

每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。

Input

第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B)

Output

一个数,即有多少头牛被所有的牛认为是受欢迎的。

Sample Input

3 3
1 2
2 1
2 3

Sample Output

1

【数据范围】
10%的数据N<=20, M<=50
30%的数据N<=1000,M<=20000
70%的数据N<=5000,M<=50000
100%的数据N<=10000,M<=50000

HINT

Source

 

你可能感兴趣的:(tar)