题目:
Monocarp 正在玩电脑游戏(又一次)。猜猜他在做什么?没错,杀怪。
一排有 n个怪物,编号从 1 到 n 。其中 i号 个怪物有两个参数:攻击值等于 ai,防御值等于 di 。为了杀死这些怪物,莫诺卡普给它们施放了狂暴咒语,因此它们会互相攻击,而不是攻击莫诺卡普的角色。
战斗由 n个回合组成。每回合都会发生以下情况:
- 首先,每个 i活着的怪物都会对左边最近的活着的怪物(如果存在)和右边最近的活着的怪物(如果存在)造成 ai 伤害;
- 然后,每个在本回合中受到超过 dj 伤害的活着的怪物 j 死亡。也就是说,当且仅当 j 怪物的防御值 dj 严格小于它在本轮受到的总伤害时,它才会死亡。
计算每一轮中死亡的怪物数量。
输入:
第一行包含一个整数 t ( 1 ≤ t ≤ 10^4) - 测试用例数。
每个测试用例由三行组成:
- 第一行包含一个整数 n ( 1≤n≤3⋅10^5 );
- 第二行包含 n 个整数 a1,a2,…,an1,2,…, ( 1≤ai≤10^9 )( 1≤ai≤10^9 );
- 第三行包含 n 个整数 d1,d2,…,dn1,2,…, ( 1≤di≤109 )。
输入的附加限制:所有测试用例的 n 之和不超过 3⋅10^5。
输出:
对于每个测试案例,打印 n 个整数。 i 个整数应该等于在 i 个回合中死亡的怪物数量。
样例1
3
5
3 4 7 5 10
4 9 1 18 1
2
2 1
1 3
4
1 1 2 4
3 3 4 2
3 1 0 0 0
0 0
1 1 1 0
思路:
首先思考一个怪物在什么情况下会死亡呢
两种情况
- 一开始的时候就被周围的怪物弄死了
- 剩下的就是第一回和没死的,假设上一回和没死的怪物,周围的怪都没死,那么他受的伤害和上一回和相同,依旧可以存活,也就是说只有上一回合旁边的怪物死了,才有可能死亡。
解决办法:
- 对于第一种情况,只能进行预处理
- 对于第二种情况,那就是记录上一回合死亡的怪物然后再出来与他相邻的怪物
怎么快速获取死亡怪物附近的两个怪物呢,可以记录左右节点,利用数组存储,实现复杂,对于连续死多个处理麻烦,利用链表,又无法快速获取下标。
使用stl容器的set,利用其中的upper_bound快速找到他的下一个位置的怪物,那么怎么找前一个呢,利用greater<int>将set反序,由于upper_bound找到的是等于自己的下一个元素,那么对于反序的就是小于自己的第一个元素,也就是前一个坐标,然后判断是否存在,在利用左右两边怪物的攻击判断是否能够击杀,能就用队列现存下来,然后再在set当中删除他的下标,再循环此操作
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define ls u << 1
#define rs u << 1 | 1
#define all(x) x.begin(),x.end()
// #define int long long
#define i128 __int128
inline int gcd(int a, int b) {return b > 0 ? gcd(b, a % b) : a;}
inline int lowbit(int x) {return x & (-x);}
int qmi(int a, int b, int mod){int res = 1;while(b) {if(b & 1) res = res * a % mod;a = a * a % mod;b >>= 1;}return res;}
inline i128 read(){i128 x = 0, f = 1;char ch = getchar();while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f;}
inline void print(i128 x){if(x < 0){putchar('-');x = -x;}if(x > 9)print(x / 10);putchar(x % 10 + '0');}
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<PII, int> PIII;
const int N = 1e5 + 10, inf = 0x3f3f3f3f, mod = 1e9 + 7;
/*
int mp[N + 1];
vector<int>prim;
void primes() {
for (int i = 2; i <= N; i++) {
if (!mp[i]) {
mp[i] = i;
prim.push_back(i);
}
for (auto p : prim) {
if (i * p > N) break;
mp[i * p] = p;
if (i % p == 0) break;
}
}
}
*/
/*
int fact[N], infact[N]; // 组合数
int C(int a, int b) {return fact[a] * infact[b] % mod * infact[a - b] % mod;}
void combination() {fact[0] = infact[0] = 1;for(int i = 1; i < N; i ++) {fact[i] = fact[i - 1] * i % mod;infact[i] = fact[i] * qmi(i, mod - 2, mod) % mod;}}
*/
void solve()
{
int n; cin >> n;
vector<int>a(n + 1, 0), d(n + 1, 0);
set<int>stx;
set<int, greater<int>>sti;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= n; i ++) cin >> d[i], stx.insert(i), sti.insert(i);
vector<int>c(n + 2, 0);
for(int j = 1; j <= n; j ++) {
c[j - 1] += a[j], c[j + 1] += a[j];
}
set<int>s;
for(int i = 1; i <= n; i ++) if(c[i] > d[i]) s.insert(i), stx.erase(i), sti.erase(i);
vector<bool>stb(n + 1, 0);
for(int j = 1; j <= n; j ++) {
cout << s.size() << ' ';
vector<int>v;
for(auto t : s) {
auto itx = stx.upper_bound(t);
int ans = 0;
if(itx != stx.end()) {
int p = *itx;
auto itxx = stx.upper_bound(p);
auto itxi = sti.upper_bound(p);
if(itxx != stx.end()) ans += a[*itxx];
if(itxi != sti.end()) ans += a[*itxi];
if(ans > d[p]) v.push_back(p);
}
auto iti = sti.upper_bound(t);
ans = 0;
if(iti != sti.end()) {
int p = *iti;
auto itix = stx.upper_bound(p);
auto itii = sti.upper_bound(p);
if(itix != stx.end()) ans += a[*itix];
if(itii != sti.end()) ans += a[*itii];
if(ans > d[p]) v.push_back(p);
}
}
s.clear();
for(auto k : v)
s.insert(k), stx.erase(k), sti.erase(k);
}
cout << '\n';
}
signed main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
}