CF1326E Bombs
题意
个数的全排列
,现在将
个数依次加入集合
,如果这个位置
上有炸弹,那么在加入这个数
后删除集合
中最大的数,当所有数加入集合后,集合中最大的数为当次花费
现在给出
个数
,对于每一个
,求第
个位置上是炸弹时,最后的花费
题解
首先一个一个放进炸弹,
只会递减
考虑现在放入炸弹
时,
是否合法
对于炸弹
来说,他只会对
间的数有影响
反之对于
来说,只有右边
的炸弹有影响
但是炸弹会先作用于比
大的数,所以只要右边大于等于
的数个数大于右边的炸弹数就行
记
为
中
的数个数减去
炸弹数
因此当前答案不合法条件就是
那么每次加入炸弹
,会令
数组
部分
每次
不合法时,
作为一个大的数,会对
间的数有影响,即
数组
部分
区间加法最值,线段树维护即可
代码
#include <bits/stdc++.h>
#define lc u<<1
#define rc u<<1|1
#define mid (t[u].l+t[u].r)/2
using namespace std;
typedef long long ll;
const int MAX = 3e5 + 10;
int N;
int p[MAX], q[MAX], pos[MAX];
struct SegmentTree {
int l, r, mx, tag;
void upd(int k) {
mx += k;
tag += k;
}
} t[MAX << 2];
void push_up(int u) { t[u].mx = max(t[lc].mx, t[rc].mx); }
void build(int u, int l, int r) {
t[u] = SegmentTree { l, r, 0, 0 };
if (l == r) return;
build(lc, l, mid); build(rc, mid + 1, r);
}
void push_down(int u) {
if (t[u].tag) {
t[lc].upd(t[u].tag);
t[rc].upd(t[u].tag);
t[u].tag = 0;
}
}
void update(int u, int ql, int qr, int k) {
if (ql <= t[u].l && t[u].r <= qr) {
t[u].upd(k);
return;
}
push_down(u);
if (ql <= mid) update(lc, ql, qr, k);
if (qr > mid) update(rc, ql, qr, k);
push_up(u);
}
int main() {
scanf("%d", &N);
for (int i = 1; i <= N; i++) scanf("%d", &p[i]), pos[p[i]] = i;
for (int i = 1; i <= N; i++) scanf("%d", &q[i]);
build(1, 1, N);
int ans = N;
printf("%d ", ans);
update(1, 1, pos[ans], 1);
for (int i = 1; i < N; i++) {
update(1, 1, q[i], -1);
while (t[1].mx <= 0) update(1, 1, pos[--ans], 1);
printf("%d ", ans);
}
return 0;
}