题目链接
题目大意:
一个序列p和一个序列q。按p1p2…pn将炸弹放到第1,2,…n的位置之上,每个炸弹都有一个值,然后q的序列是表示当前qi的位置上已经存在炸弹,如果已经存在炸弹,就把当前已经放的(包括正在放的)中的最大值移除,最后输出剩余的炸弹中的最大值。对每个qi的前缀都要询问一下。
解题思路:
很容易就看到因为前缀越长则删除的个数越多所以答案肯定是非递增。
按照题解思路,假设当前答案为x-1,则≥x的所有的炸弹都要被清除掉,一个炸弹需要被清除掉则需要有一个qi≥当前的位置。所以假设一个数组b,b[i]表示[i…n]这个后缀中≥x的个数- [i…,n]中的已经存在炸弹数,在所有的b[i]都≤0的时候就说明≥x的炸弹都被清除掉了。这用线段树的最大值维护查询t[1]就行了。
然后首先把[1…pos[n]]插入线段树,然后每次碰到一个q[i]就把[1…q[i]]的值都-1,如果当前的t[1]>0则说明当前值没有被全部清除直接输出就行了,否则就将答案ans–,每次递减后将[1…pos[ans]]的值+1,直到t[1]>0就说明≥ans的炸弹没有被全部清除,那就是答案了。
#include<bits/stdc++.h>
using namespace std;
mt19937 rng_32(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
const int maxn=3e5+10;
int t[maxn<<2],lz[maxn<<2];
void pushup(int i)
{
t[i]=max(t[i<<1],t[i<<1|1]);
}
void pushdown(int i)
{
if (lz[i])
{
t[i<<1]+=lz[i];
lz[i<<1]+=lz[i];
t[i<<1|1]+=lz[i];
lz[i<<1|1]+=lz[i];
lz[i]=0;
}
}
void update(int l,int r,int i,int ql,int qr,int add)
{
if (ql<=l && qr>=r)
{
t[i]+=add;
lz[i]+=add;
return ;
}
pushdown(i);
int mid=(l+r)>>1;
if (ql<=mid)
update(l,mid,i<<1,ql,qr,add);
if (qr>mid)
update(mid+1,r,i<<1|1,ql,qr,add);
pushup(i);
}
int a[maxn],b[maxn];
int pos[maxn];
int main()
{
int n;
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>a[i];
pos[a[i]]=i;
}
for (int i=1;i<=n;i++)
cin>>b[i];
int ans=n;
update(1,n,1,1,pos[n],1);
cout<<n<<" ";
for(int i=1;i<n;i++)
{
update(1,n,1,1,b[i],-1);
if (t[1]>0)
{
cout<<ans<<" ";
}
else
{
while (t[1]<=0)
{
ans--;
update(1,n,1,1,pos[ans],1);
}
cout<<ans<<" ";
}
}
return 0;
}