EOJ Monthly 2021.10
比赛链接
EOJ Monthly 2021.10
B. Secret
众所周知,在苹果发布会前,所有即将被公布的新产品都是绝密。
我们可以认为苹果的所有员工之间的关系构成一张关系图,两个员工的关系密切,则两个员工之间会有一条边相连(给我们认为关系是双向的),员工的索引是从 \(1\) 到 \(n\) 递增的整数,假设每条边的长度都是 \(1\) 。
现在,苹果即将召开新的一次发布会了,在发布会前,高层将会有一次秘密会议,讨论决定发布会的具体内容,显然,秘密会议的内容是绝对的商业机密。
可惜的是,参与会议的人都是些藏不住秘密的人。从会议结束后的第一天开始,所有知道秘密的人都会和距离(在上述关系图中的距离)自己不超过 \(k\) 的所有人共享这个秘密,而第二天,所有知道秘密的人都会和距离自己不超过 \(2k\) 的所有人共享这个秘密。也就是说,在会议结束后的第 \(x\) 天,所有知道秘密的人都开始与距自己最多 \(x\times k\) 的所有人共享该秘密。
现在 Cuber QQ 被委托计算每个人都会在什么时候知道这个秘密。
输入格式
第一行包含四个整数 \(n, m,q\) 和 \(k(1\leq n,q,k \leq 10^5,q \leq n,1 \leq m\ 2\times 10^5)\) ,分别表示员工数量,关系数量,参加秘密会议的人数,以及任务描述中的 \(k\)。
接下来的一行包含 \(q\) 个整数,其中第 \(i\) 个整数表示秘密会议中第 \(i\) 个员工的索引。
接下来的 \(m\) 行,每行包含两个整数 \(a_i\) 和 \(b_i\) \((1\leq a_i.b_i \leq n,a_i \neq b_i)\),表示第 \(i\) 个关系为索引为 \(a_i\) 和 \(b_i\) 的员工。
题目保证给定的图是一张联通图,即任意两个员工之间,一定存在间接的关系相连。
输出格式
输出 \(n\) 个数字,第 \(i\) 个数字代表会议后的哪一天索引为 \(i\) 的员工将知道秘密。如果该员工参加了会议,则输出 \(0\) 。
input
6 8 1 1
6
1 3
1 5
1 6
2 5
2 6
3 4
3 5
5 6
output
1 1 2 2 1 0
解题思路
多源最短路
每条边都为1,可以用bfs
求解,将所有源点放入队列里,其余操作跟求深度一样,最后根据这个最短路可推导出天数~
- 时间复杂度:\(O(n+m)\)
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,Q,k;
bool v[N];
int d[N];
int day[N];
vector<int> adj[N];
void bfs()
{
queue<int> q;
for(int i=1;i<=n;i++)
if(v[i])q.push(i);
while(q.size())
{
int x=q.front();
q.pop();
for(int y:adj[x])
{
if(v[y])continue;
d[y]=d[x]+1;
v[y]=true;
q.push(y);
}
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&Q,&k);
for(int i=1;i<=Q;i++)
{
int x;
scanf("%d",&x);
v[x]=true;
}
int x,y;
while(m--)
{
scanf("%d%d",&x,&y);
adj[x].push_back(y),adj[y].push_back(x);
}
bfs();
int cnt;
for(cnt=1;;cnt++)
{
day[cnt]=k*(1+cnt)*cnt/2;
if(day[cnt]>n)break;
}
for(int i=1;i<=n;i++)printf("%d ",lower_bound(day,day+cnt+1,d[i])-day);
return 0;
}