codeforces CF949C Data Center Maintenance Tarjan强连通分量

$ \rightarrow $ 戳我进CF原题

  • 有 $ 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;
}

猜你喜欢

转载自www.cnblogs.com/PotremZ/p/9447443.html
今日推荐