CF1326E Bombs 题解
题目描述
给定排列 \(p_i,q_i\) ,在数轴的第 \(i\) 个位置上摆放了一个数 \(p_i\) 。
现在依次加入炸弹,第 \(i\) 次在 \(q_i+0.5\) 的位置加入一个炸弹,然后从左往右扫描,扫到第 \(i\) 个位置时把 \(p_i\) 加入大根堆中,扫到一个炸弹就 \(\texttt{pop}\) 掉堆顶。
在每一次加入炸弹前,求最终堆顶元素。
数据范围
- \(1\le n\le 3\cdot 10^5\) 。
- \(1\le p_i,q_i\le n\) ,保证 \(p,q\) 为排列。
时间限制 \(\texttt{3s}\) ,空间限制 \(\texttt{256MB}\) 。
分析
容易发现加入炸弹的过程中,最终堆顶元素会不断变小。
双指针,问题转化为已知加入了若干炸弹,询问堆顶能否 \(\ge x\) 。
把 \(p_i\ge x\) 的位置全部拿出来,如果堆顶 \(<x\) ,那么每个 \(p_i\) 都有一个炸弹与之匹配。
换言之,如果把 \(p_i\ge x\) 的位置看成单点 \(+1\) ,把炸弹看成单点 \(-1\) ,那么堆顶 \(\lt x\) 当且仅当任意一个后缀权值和都 \(\le 0\)。
单点加、查询全局后缀 \(\max\) ,转化成前缀加、查询全局 \(\max\) ,线段树维护即可。
时间复杂度 \(\mathcal O(n\log n)\) 。
#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
int n,pos[maxn];
int read()
{
int q=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=10*q+ch-'0',ch=getchar();
return q;
}
struct node
{
int l,r,add,mx;
}f[4*maxn];
void pushadd(int p,int v)
{
f[p].add+=v,f[p].mx+=v;
}
void pushdown(int p)
{
if(f[p].add==0) return ;
pushadd(2*p,f[p].add),pushadd(2*p+1,f[p].add);
f[p].add=0;
}
void pushup(int p)
{
f[p].mx=max(f[2*p].mx,f[2*p+1].mx);
}
void build(int p,int l,int r)
{
f[p].l=l,f[p].r=r;
if(l==r) return ;
int mid=(l+r)/2;
build(2*p,l,mid);
build(2*p+1,mid+1,r);
pushup(p);
}
void modify(int p,int l,int r,int v)
{
if(l<=f[p].l&&f[p].r<=r)
{
pushadd(p,v);
return ;
}
if(l>f[p].r||r<f[p].l) return ;
pushdown(p);
modify(2*p,l,r,v);
modify(2*p+1,l,r,v);
pushup(p);
}
int main()
{
build(1,1,n=read());
for(int i=1;i<=n;i++) pos[read()]=i;
modify(1,1,pos[n],1),printf("%d ",n);
for(int i=1,j=n;i<n;i++)
{
modify(1,1,read(),-1);
while(j&&f[1].mx<=0) modify(1,1,pos[--j],1);
printf("%d ",j);
}
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/16115523.html
浙公网安备 33010602011771号