21.11.16模拟 问题


你需要完成 n 道题目。有一些题目是相关的,当你做一道题的时候,如果你之前做过对它有帮助的题目,你会更容易地做出它。帮助关系具有传递性,如果题目 x 对题目 y 有帮助,题目 y 对题目 z 有帮助,那么题目x 对题目 z 也有帮助(尽管 x,z 可能不在输入中)。你可以自由安排做题的顺序。现在,你想要知道,你在完成所有题目的情况下,可能有多少道题目是在有帮助的情况下完成的。

缩点,然后可以缩成几条链。然后答案就是 n-强连通分量数 到 n-链数

const int N = 1e5 + 79;
const int M = 3e5 + 79;
struct graph {
	int head[N], tot, next[M], ver[M];
	inline void add(int a, int b) {
		ver[++tot] = b;
		next[tot] = head[a];
		head[a] = tot;
	}
} G, C;
int n, m;
int dfn[N], tim, low[N];
int s[N], top;
int ins[N], cnt;
int color[N], sum[N], r[N];
int in[N], ot[N], siz[N];
bool vis[N];
int t;
inline void  dfs(int x) {
	if(vis[x]) return;
	vis[x] = 1;
	++t;
	repc(x)
	dfs(C.ver[i]);
}

inline void tarjan(int x) {
	low[x] = dfn[x] = ++tim;
	s[++top] = x;
	ins[x] = 1;
	repg(x) {
		int y(G.ver[i]);
		if(!dfn[y]) {
			tarjan(y);
			low[x] = min(low[x], low[y]);
		} else if(ins[y]) {
			low[x] = min(low[x], dfn[y]);
		}
	}
	if(low[x] == dfn[x]) {
		int y;
		++cnt;
		do {
			y = s[top--];
			++siz[cnt];
			ins[y] = 0;
			color[y] = cnt;
		} while(x != y);
	}
}
/*
2 1
1 2
0
1
*/


int main() {
	freopen("problem.in", "r", stdin);
	freopen("problem.out","w",stdout);
	read(n);
	read(m);
	int x, y;
	rep(i, 1, m) {
		read(x);
		read(y);
		G.add(x, y);
	}

	rep(i, 1, n) {
		if(!dfn[i]) {
			tarjan(i);
		}
	}
	rep(x, 1, n) {
		repg(x) {
			int y(G.ver[i]);
			if(color[y] == color[x]) continue;
			C.add(color[x], color[y]);
			++ot[color[x]];
			++in[color[y]];
		}
	}
	int k(0);
	rep(i, 1, cnt) {
		if(in[i]) continue;
		++k;
		dfs(i);
	}
	rep(i, n-t, n - k) {
		out(i, '\n');
	}
	return 0;
}