CF1922D. Berserk Monsters

思路

题目大意是说每人每回合可以释放一次威力为\(a_i\)的技能攻击两边的人,问你每回合会死多少人。这种会改变左右联系的关系,我们用链表来表示,\(l_i表示i左边的联系、r_i表示i右边的联系\)。接着我们考虑怎么计算出每回合死掉的人,首先,直接暴力肯定是不行,我们可以用一个\(set_s\)记录下当前回合可能会死的人,然后遍历这个set找出本回合真正会死的人将他们的位置插入到另一个\(set_d\)中,然后清空\(set_s\),遍历\(set_d\)\(set_d\)中每个元素的左右联系都插入\(set_s\)中,如此反复n轮

ac代码

#include <bits/stdc++.h>

using namespace std;
using i64 = long long;
const i64 inf = 1e18;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int N = 3e5 + 10;

int a[N], b[N], l[N], r[N];

void solve() {
    int n;
    cin >> n;
    bitset<N> vis;
    iota(a + 1, a + n + 1, 1);
    set<int> s(a + 1, a + n + 1);

    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        a[i + 1] = 0;
        l[i] = i - 1;
        r[i] = i + 1;
    }
    for (int i = 1; i <= n; i++) {
        cin >> b[i];
        b[i + 1] = 0;
    }

    for (int i = 1; i <= n; i++) {
        set<int> d;
        int ans = 0;

        for (auto x : s) {
            if (vis[x]) continue;

            if (a[l[x]] + a[r[x]] > b[x]) {
                ans ++;
                vis[x] = 1;
                d.insert(x);
            }
        }

        s.clear();

        for (auto x : d) {
            if (l[x] != 0) s.insert(l[x]);
            if (r[x] != n + 1) s.insert(r[x]);

            r[l[x]] = r[x];
            l[r[x]] = l[x];
        }

        cout << ans << " \n"[i == n];
    }

}   

int main() {
    ios::sync_with_stdio(0); cin.tie(0);
    cout.tie(0);

    int t = 1;
    cin >> t;
    while (t --) solve();

    return 0;
}
posted @ 2024-01-22 00:25  jvdyvan  阅读(41)  评论(0)    收藏  举报