cf950e Data Center Maintenance

若推迟 (u) 必推迟 (v),则连边 <(u,v)>。
求强联通分量后缩点,答案显然是出度为 (0) 且 size 最小的 scc。

#include <iostream>
#include <cstdio>
using namespace std;
int n, m, h, a[100005], dfn[100005], uu, vv, loo[100005], bel[100005], scc, hav[100005], sta[100005], din, tot;
int hea[100005], cnt, ru[100005], ans=0x3f3f3f3f, chu[100005], minn;
bool ins[100005];
struct Edge{
	int too, nxt;
}edge[200005];
void add_edge(int fro, int too){
	edge[++cnt].nxt = hea[fro];
	edge[cnt].too = too;
	hea[fro] = cnt;
}
void tarjan(int x){
	sta[++din] = x;
	ins[x] = true;
	dfn[x] = loo[x] = ++tot;
	for(int i=hea[x]; i; i=edge[i].nxt){
		int t=edge[i].too;
		if(!dfn[t]){
			tarjan(t);
			loo[x] = min(loo[x], loo[t]);
		}
		else if(ins[t])
			loo[x] = min(loo[x], dfn[t]);
	}
	if(dfn[x]==loo[x]){
		int j;
		scc++;
		do{
			j = sta[din--];
			bel[j] = scc;
			hav[scc]++;
			ins[j] = false;
		}while(dfn[j]!=loo[j]);
	}
}
int main(){
	cin>>n>>m>>h;
	for(int i=1; i<=n; i++)
		scanf("%d", &a[i]);
	for(int i=1; i<=m; i++){
		scanf("%d %d", &uu, &vv);
		if((a[uu]+1)%h==a[vv])	add_edge(uu, vv);
		if((a[vv]+1)%h==a[uu])	add_edge(vv, uu);
	}
	for(int i=1; i<=n; i++)
		if(!dfn[i])
			tarjan(i);
	for(int i=1; i<=n; i++)
		for(int j=hea[i]; j; j=edge[j].nxt){
			int t=edge[j].too;
			if(bel[i]!=bel[t])
				chu[bel[i]]++;
		}
	for(int i=1; i<=scc; i++)
		if(!chu[i] && ans>hav[i]){
			ans = hav[i];
			minn = i;
		}
	cout<<ans<<endl;
	for(int i=1; i<=n; i++)
		if(bel[i]==minn)
			printf("%d ", i);
	printf("
");
	return 0;
}
原文地址:https://www.cnblogs.com/poorpool/p/8543519.html