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;
}