题解 [HAOI2006]受欢迎的牛

到现在才来学强连通分量QaQ

注意理解非树边对low的更新:
只有返祖边入点的dfn和入点未划到强连通分量里的横叉边才是合理的更新low。其他非树边均不可。然后根据dfs的性质,应当判断非树边指向的点有没有加入强连通分量。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 12345, M = 56789;
int head[N], ver[M], nex[M], my[M], tot;
inline void addedge(int u, int v) {
	ver[tot] = v; nex[tot] = head[u]; my[tot] = u; head[u] = tot++;
}

int dfn[N], low[N], cl[N], sta[N], outd[N], num[N], top = 0, dfs_clock = 1, col = 1;
void dfs(int cur) {
	dfn[cur] = low[cur] = dfs_clock++;
	sta[top++] = cur;
	for(int i = head[cur]; ~i; i = nex[i]) {
		if(!dfn[ver[i]]) {
			dfs(ver[i]);
			low[cur] = min(low[cur], low[ver[i]]);
		} else if(!cl[ver[i]]) {
			low[cur] = min(low[cur], dfn[ver[i]]);
		}
	}
	if(dfn[cur] == low[cur]) {
		--top;
		while(sta[top] != cur) {
			cl[sta[top]] = col;
			++num[col];
			--top;
		}
		cl[cur] = col;
		++num[col];
		++col;
	}
}

int main() {
	memset(head, -1, sizeof(head));
	int n, m, u, v, tms = 0, ans;
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= m; ++i) {
		scanf("%d %d", &u, &v);
		addedge(u, v);
	}
	for(int i = 1; i <= n; ++i) if(!dfn[i]) 
		dfs(i);
	for(int i = 0; i < tot; ++i) {
		if(cl[my[i]] != cl[ver[i]]) {
			++outd[cl[my[i]]];
		}
	}
	for(int i = 1; i < col; ++i)
		if(!outd[i]) {
			++tms;
			ans = num[i];
		}
	if(tms == 1) {
		printf("%d\n", ans);
	} else {
		printf("0\n");
	}
	return 0;	
}