答案具有單調性,,考慮枚舉 ,判斷 是否成立。
若 成立,則所有 的值都要被炸掉,把這些值拿出來按下標排序,最左邊的數右邊要有至少 個炸彈,最右邊的數至少要有 個炸彈,第 個數的右邊至少要有 個炸彈。
對於每個 ,從大到小枚舉 ,若 都能被炸彈炸掉,則 。對於所有 的值,維護每個數字需要的炸彈數量,即炸彈需求量,在 放一個炸彈,則 的數值對炸彈的需求量減一,枚舉 ,將 插入序列,則 的炸彈需求量加一,只要當前這個序列任意一個炸彈需求量大於0,則表明答案 ,這個可以用線段樹維護區間最值。
由於 具有單調性,因此 只需要枚舉一遍,複雜度
代碼:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 10;
int n,p[maxn],q[maxn],ans[maxn],pos[maxn];
struct seg_tree {
int val[maxn << 2],add[maxn << 2];
#define lson rt << 1,l,mid
#define rson rt << 1 | 1,mid + 1,r
void build(int rt,int l,int r) {
add[rt] = val[rt] = 0;
if (l == r) return ;
int mid = l + r >> 1;
build(lson); build(rson);
}
void pushdown(int rt) {
if (!add[rt]) return ;
val[rt << 1] += add[rt];
add[rt << 1] += add[rt];
val[rt << 1 | 1] += add[rt];
add[rt << 1 | 1] += add[rt];
add[rt] = 0;
}
void update(int L,int R,int v,int rt,int l,int r) {
if (L <= l && r <= R) {
val[rt] += v;
add[rt] += v;
return ;
}
pushdown(rt);
int mid = l + r >> 1;
if (L <= mid) update(L,R,v,lson);
if (mid + 1 <= R) update(L,R,v,rson);
val[rt] = max(val[rt << 1],val[rt << 1 | 1]);
}
}tree;
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]);
tree.build(1,1,n);
int cur = n;
tree.update(1,pos[cur],1,1,1,n);
for (int i = 1; i <= n; i++) {
ans[i] = cur;
tree.update(1,q[i],-1,1,1,n);
while (cur > 1 && tree.val[1] <= 0) {
cur--;
tree.update(1,pos[cur],1,1,1,n);
}
}
for (int i = 1; i <= n; i++)
printf("%d ",ans[i]);
return 0;
}