卧薪尝胆,厚积薄发。
Data Center Maintenance
Date: Sun Jul 08 21:43:02 CST 2018
In Category:
NoCategory
Description:
有
$n$
个信息中心,第
$i$
个信息中心要在第
$t_i$
个小时维护,维护期间信息不能被获得。
每个用户的数据都有两份备份,第
$i$
个用户的数据放在信息中心
$c_{i,1}$
和
$c_{i,2}$
。
现在要挑选一个尽量小的信息中心集合,使得将这个集合的维护时间推迟一个小时后,仍然能保证每个用户的数据在任意时刻都能获得。
$2\le n \le10^5$
Solution:
如果
$t_{c_{i,1}}+1=t_{c_{i,2}}$
则连边
$c_{i,1}\to c_{i,2}$
,代表如果推迟
$c_{i,1}$
则必须推迟
$c_{i,2}$
,反之亦然,这样求出出度为
$0$
的最小的
$SCC$
即为答案。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<stack>
#include<cstring>
using namespace std;
int n,m,h;
#define MAXN 100010
int t[MAXN];
struct edge
{
int to,nxt;
}e[MAXN << 2];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b)
{
++edgenum;e[edgenum].to = b;e[edgenum].nxt = lin[a];lin[a] = edgenum;
return;
}
stack<int> s;
int dfn[MAXN],low[MAXN],tot = 0;
bool v[MAXN];
int ins[MAXN],siz[MAXN];
int scc = 0;
void tarjan(int k)
{
dfn[k] = low[k] = ++tot;
s.push(k);v[k] = true;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(dfn[e[i].to] == 0)
{
tarjan(e[i].to);
low[k] = min(low[k],low[e[i].to]);
}
else if(v[e[i].to])
{
low[k] = min(low[k],dfn[e[i].to]);
}
}
if(low[k] >= dfn[k])
{
int t;
++scc;
do
{
t = s.top();s.pop();
v[t] = false;ins[t] = scc;
siz[scc]++;
}while(t != k);
}
return;
}
int deg[MAXN];
int main()
{
scanf("%d%d%d",&n,&m,&h);
for(int i = 1;i <= n;++i)
{
scanf("%d",&t[i]);
}
int c1,c2;
for(int i = 1;i <= m;++i)
{
scanf("%d%d",&c1,&c2);
if((t[c1] + 1) % h == t[c2])add(c1,c2);
if((t[c2] + 1) % h == t[c1])add(c2,c1);
}
for(int i = 1;i <= n;++i)
{
if(dfn[i] == 0)
{
tarjan(i);
}
}
memset(deg,0,sizeof(deg));
for(int k = 1;k <= n;++k)
{
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(ins[k] != ins[e[i].to])
{
++deg[ins[k]];
}
}
}
int ans = -1;
for(int i = 1;i <= scc;++i)
{
if(deg[i] == 0)
{
if(ans == -1 || siz[i] < siz[ans])
{
ans = i;
}
}
}
cout << siz[ans] << endl;
for(int i = 1;i <= n;++i)
{
if(ins[i] == ans)
{
printf("%d ",i);
}
}
puts("");
return 0;
}
In tag:
图论-tarjan
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡