题目链接
考虑离线回答这个问题,由于只问我们第 位,我们很自然想到枚举一个阈值,将大于等于它的变成 ,小于它的变成 ,然后对这个 01 序列进行排序操作。有单调性,举个栗子:
假设知道一个排完序后的序列 ,现询问第 个位置。
若选 作为阈值,排序好的 01 序列为 ,第 个位置为 。
若选 作为阈值,排序好的 01 序列为 ,第 个位置为 。
若选 作为阈值,排序好的 01 序列为 ,第 个位置为 。
若选 作为阈值,排序好的 01 序列为 ,第 个位置为 。
若选 作为阈值,排序好的 01 序列为 ,第 个位置为 。
可以发现,最大的满足第 个位置为 的阈值就是答案。若阈值偏小,则该位置为 ;若阈值偏大,则该位置为 。所以满足单调性,二分答案即可。
还有一个问题,如何快速对 01 序列排序。我们只需要知道这个序列中 的个数,再根据升序还是降序,决定这几个 放最前还是最后。用线段树进行区间求和以及区间修改即可。
注意特判全是 或 的情况,不然区间修改会 RE。
#include<bits/stdc++.h>
#define ls p*2
#define rs p*2+1
using namespace std;
void read(int &x)
{
char ch=getchar();
int r=0,w=1;
while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
while(isdigit(ch))r=(r<<3)+(r<<1)+(ch^48),ch=getchar();
x=r*w;
}
const int N=1e5+7;
int a[N],n,m,q,b[N],sum[N*4],lazy[N*4],size[N*4],ans;
struct sbt
{
int op,l,r;
}qt[N];
void update(int p)
{
sum[p]=sum[ls]+sum[rs];
size[p]=size[ls]+size[rs];
}
void pushdown(int p)
{
lazy[ls]=lazy[p];
sum[ls]=size[ls]*lazy[p];
lazy[rs]=lazy[p];
sum[rs]=size[rs]*lazy[p];
lazy[p]=-1;
}
void build(int p,int l,int r)
{
lazy[p]=-1;
if(l==r)
{
sum[p]=b[l];
size[p]=1;
return;
}
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
update(p);
}
void change(int p,int l,int r,int x,int y,int k)
{
if(x<=l&&r<=y)
{
lazy[p]=k;
sum[p]=size[p]*k;
return;
}
if(lazy[p]!=-1)pushdown(p);
int mid=l+r>>1;
if(x<=mid)change(ls,l,mid,x,y,k);
if(y>mid)change(rs,mid+1,r,x,y,k);
update(p);
}
void query(int p,int l,int r,int x,int y)
{
if(x<=l&&r<=y)
{
ans+=sum[p];
return;
}
if(lazy[p]!=-1)pushdown(p);
int mid=l+r>>1;
if(x<=mid)query(ls,l,mid,x,y);
if(y>mid)query(rs,mid+1,r,x,y);
}
bool check(int x)
{
for(int i=1;i<=n;i++)
b[i]=a[i]>=x?1:0;
build(1,1,n);
for(int i=1;i<=m;i++)
{
int op=qt[i].op,l=qt[i].l,r=qt[i].r;
ans=0;
query(1,1,n,l,r);
if(ans==r-l+1||ans==0)continue;
if(!op)
{
change(1,1,n,l,r-ans,0);
change(1,1,n,r-ans+1,r,1);
}
else
{
change(1,1,n,l,l+ans-1,1);
change(1,1,n,l+ans,r,0);
}
}
ans=0;
query(1,1,n,q,q);
return ans==1;
}
int main()
{
read(n);read(m);
for(int i=1;i<=n;i++)
read(a[i]);
for(int i=1;i<=m;i++)
read(qt[i].op),read(qt[i].l),read(qt[i].r);
read(q);
int l=1,r=n,ans;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid))ans=mid,l=mid+1;
else r=mid-1;
}
cout<<ans;
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通