题意
有n个信息中心,第i个信息中心要在第ti时刻维护,每个用户都将资料存档在了两个中心,你现在要选一个最小的集合,使得维修时间推迟一小时后,用户还能获得信息
思路
对于每对冲突的点连边,然后求强连通分量,答案就是缩点后度数为零且最小的SCC
代码
//By AcerMo%%%尹兄
#include<cmath>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=200500;
int n,m,h;
int low[M],dfn[M],fa[M],in[M];
int vis[M],ind=0,ti=0,t[M],siz[M];
stack<int>s;
vector<int>v[M];
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void tarjan(int x)
{
low[x]=dfn[x]=++ind;vis[x]=1;s.push(x);
for (int i=0;i<v[x].size();i++)
{
int go=v[x][i];
if (!dfn[go])
{
tarjan(go);
low[x]=min(low[x],low[go]);
}
else if (vis[go])
low[x]=min(low[x],dfn[go]);
}
if (low[x]==dfn[x])
{
ti++;int u=-1;
while (u!=x)
{
u=s.top();s.pop();
vis[u]=0;fa[u]=ti;
siz[ti]++;
}
}
return ;
}
int main()
{
n=read();m=read();h=read();
for (int i=1;i<=n;i++) t[i]=read();
for (int i=1;i<=m;i++)
{
int x=read(),y=read();
if (t[x]==(t[y]+1)%h) v[y].push_back(x);
if (t[y]==(t[x]+1)%h) v[x].push_back(y);
}
for (int i=1;i<=n;i++)
if (!dfn[i]) tarjan(i);
for (int i=1;i<=n;i++)
for (int k=0;k<v[i].size();k++)
if (fa[i]!=fa[v[i][k]]) in[fa[i]]++;
siz[0]=n+1;int ans=0;
for (int i=1;i<=ti;i++)
if (!in[i]&&siz[i]<siz[ans]) ans=i;
cout<<siz[ans]<<endl;
for (int i=1;i<=n;i++)
if (fa[i]==ans)
cout<<i<<" ";
return 0;
}