题解 - 战前筹备

题目描述

竞赛代替不了战争,就像葡萄酒代替不了鲜血。 ——《光荣与梦想》
机房战争的爆发已是不可避免的,IAKIOI的字句已潜伏在地方的剪贴板里,#define main mian和#define sort random_shuffle的代码也在硬盘阴暗的角落里蠢蠢欲动,自动盗取 QQ ,Luogu 账号的软件隐没在庞大的 Windows 文件夹的迷雾中,等待着钩子函数陷阱的触发。
你深深地懂得自己身处战场中央就无法置身事外的道理,准备利用地理优势打一场漂亮的阵地战,并准备算出机房里每个位置会受到的打击以找到最安全的位置。具体地,机房是一张 n 个点, m 条边的简单图,每个点都有一个人,一个人可以机惨他身旁的所有人,若这一时刻一个人被机惨,那么下一时刻他会报复性机惨能机惨到的所有人(若一个时刻它被机惨多次只会报复一次),同时,如果编号为 i 的位置的人被机惨的次数大于等于这个位置的防御力 di, 他将因 AKIOI 而社死并退出战斗,即以后别人不会再机惨他,他也不会在下一轮报复机惨。若一开始由一号点开始机惨身边的所有人,求每个位置的被机惨次数。

输入

第一行两个整数为 n 和 m 表示机房这张图的点数和边数。
第二行 n 个整数 di 表示每个位置的防御力。
第三行到第 m+2 行,每行两个整数,表示这两个点之间有一条边。

输出

一行 n 个整数,第 i 个整数 ansi 表示编号为 i 的位置收到的攻击次数。

样例

样例输入

5 4
1 1 3 5 1
1 3
2 4
4 3
5 4

样例输出

1 1 3 2 1

提示

对10%的数据保证 n≤2, m ≤100000 di ≤10
对30%的数据保证 n≤10, m ≤100000 di ≤10
对100%的数据保证 n ≤100,m ≤100000,di ≤100

分析

BFS

从1号点开始BFS,队列中存储节点的编号以及当前的时间,并且记录下每个点的死亡时间(dead)和开始攻击的时间(st)

若当前时间>=死亡时间,已经死亡,退出战斗;否则,被攻击次数+1

若被攻击后血量为0,则记录下死亡时间

若当前时间>=开始攻击的时间,则入队

实现

void bfs(){
    memset(dead,0x3f,sizeof dead);
 
    queue<PII> q;
    q.push({1,1});
    st[1] = 1;
 
    while(!q.empty()){
        int u = q.front().first,t = q.front().second;
        q.pop();
 
        if(t >= dead[u]) continue;
        for(int i = h[u];i != -1;i = ne[i]){
            int j = e[i];
             
            d[j]--;
            if(!d[j]) dead[j] = t + 1;
            if(t < dead[j]) cnt[j]++;
            if(t >= st[j]){
                q.push({j,t + 1});
                st[j] = t + 1;
            }
        }
    }
}

代码

#include<bits/stdc++.h>
 
using namespace std;
 
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 100 + 10,M = 100000 + 10;
 
int n,m;
int d[N],back_d[N];
int h[N],e[M * 2],ne[M * 2],idx;
int dead[N],st[N],cnt[N];
 
void add(int A,int B){
    e[idx] = B,ne[idx] = h[A],h[A] = idx++;
}
 
void bfs(){
    memset(dead,0x3f,sizeof dead);
 
    queue<PII> q;
    q.push({1,1});
    st[1] = 1;
 
    while(!q.empty()){
        int u = q.front().first,t = q.front().second;
        q.pop();
 
        if(t >= dead[u]) continue;
        for(int i = h[u];i != -1;i = ne[i]){
            int j = e[i];
             
            d[j]--;
            if(!d[j]) dead[j] = t + 1;
            if(t < dead[j]) cnt[j]++;
            if(t >= st[j]){
                q.push({j,t + 1});
                st[j] = t + 1;
            }
        }
    }
}
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
 
    memset(h,-1,sizeof h);
 
    cin >> n >> m;
    for(int i = 1;i <= n;i++){
        cin >> d[i];
        back_d[i] = d[i];
    } 
 
    for(int i = 1,a,b;i <= m;i++){
        cin >> a >> b;
        add(a,b),add(b,a);
    }
 
    bfs();
 
    for(int i = 1;i <= n;i++) cout << min(back_d[i],cnt[i]) << ' ';
 
    return 0;
}
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值