有 $ n $ 个信息中心,第 $ i $ 个信息中心要在第 $ t_i $ 个小时维护,维护期间信息不能被获得。
每个用户的数据都有两份备份,第 $ i $ 个用户的数据放在信息中心 $ c_{i,1} $ 和 $ c_{i,2} $ 。
现在要挑选一个尽量小的信息中心合集,使得将这个集合的维护时间推迟一个小时后,仍然能保证每个用户的数据在任意时刻都能获得。
$ n \le 100000 $
对于每个$ c_{i,1} , c_{i,2} $ 若调整 $ c_{i,1} $ 后与 $ c_{i,2} $ 的维护时间冲突 则连边$ (c_{i,1} , c_{i,2} )$
对于$ c_{i,2} , c_{i,1} $ 亦然
求出强连通分量,所求集合即为缩点后度数为0的最小的 $ SCC $
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
#define maxn 100005
stack<int>s;
vector<int>e[maxn],sct[maxn];
int dfn[maxn],low[maxn],tim,bel[maxn],scc;
bool vis[maxn];
void tarjan(int u){
dfn[u]=low[u]=++tim; vis[u]=1; s.push(u);
for(int v,i=0;i<e[u].size();++i)
if(!dfn[v=e[u][i]]){
tarjan(v);
low[u]=min(low[v],low[u]);
} else if(vis[v])
low[u]=min(dfn[v],low[u]);
if(dfn[u]==low[u]){
++scc;
do{
u=s.top(); s.pop(); vis[u]=0;
bel[u]=scc;
sct[scc].push_back(u);
}while(dfn[u]!=low[u]);
}
}
int n,deg[maxn];
inline void shrink_point(){
for(int i=1;i<=n;++i)
for(int j=0;j<e[i].size();++j)
if(bel[i]!=bel[e[i][j]])
++deg[bel[i]];
}
int m,h,t[maxn],ans,siz=maxn;
int main(){
scanf("%d %d %d",&n,&m,&h);
for(int i=1;i<=n;++i) scanf("%d",&t[i]);
for(int u,v,i=1;i<=m;++i){
scanf("%d %d",&u,&v);
if((t[u]+1)%h==t[v]) e[u].push_back(v);
if((t[v]+1)%h==t[u]) e[v].push_back(u);
}
for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
shrink_point();
for(int i=1;i<=scc;++i)
if(deg[i]==0&&sct[i].size()<siz){ ans=i; siz=sct[i].size(); }
printf("%d\n",sct[ans].size());
sort(sct[ans].begin(),sct[ans].end());
for(int i=0;i<sct[ans].size();++i) printf("%d ",sct[ans][i]);
return 0;
}