题解 [HEOI2016/TJOI2016] 排序
看到这道题按照套路首先想到二分答案(即二分 位置上的数,记作 )。
再按照套路将大于 的数字设为 ,将等于 的数设为 ,小于 的数字设为 。
那么对于区间 操作,应该先讲 的数量找出来,然后按照从小到大的顺序 进行区间赋值,并支持区间求和,这用线段树维护即可。而 的情况也是同理。
现在考虑二分指针如何移动。首先, 两者并不满足单调性,也就是说, 增大,位置不一定取得到后面,减小同理。这时便要从另一个角度思考问题。
如果 是 ,说明答案比当前数字大,我们将指针右移;,说明答案正好是 ;,说明答案比当前数字小,将指针左移。
#include<bits/stdc++.h> using namespace std; typedef long long LL; inline int read() { int sum=0,flag=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') flag=-1; c=getchar();} while(c>='0'&&c<='9') {sum=sum*10+c-'0'; c=getchar();} return sum*flag; } const int N=1e5+10; int n,m,q; int a[N]; int ql[N],qr[N],qt[N]; int tr[N<<2][3],tag[N<<2][3]; struct node { int a0,a1,a2; friend node operator + (node x,node y) { return {x.a0+y.a0,x.a1+y.a1,x.a2+y.a2}; } }; inline void pushup(int nd) { for(int i=0;i<=2;i++) tr[nd][i]=tr[nd<<1][i]+tr[nd<<1|1][i]; } inline void add(int nd,int l,int r,int a0,int a1,int a2) { tr[nd][0]=tr[nd][1]=tr[nd][2]=0; tag[nd][0]=tag[nd][1]=tag[nd][2]=0; if(a0) {tr[nd][0]=r-l+1; tag[nd][0]=1;} if(a1) {tr[nd][1]=r-l+1; tag[nd][1]=1;} if(a2) {tr[nd][2]=r-l+1; tag[nd][2]=1;} } inline void pushdown(int nd,int l,int r) { if(!tag[nd][0]&&!tag[nd][1]&&!tag[nd][2]) return ; int mid=l+r>>1; add(nd<<1,l,mid,tag[nd][0],tag[nd][1],tag[nd][2]); add(nd<<1|1,mid+1,r,tag[nd][0],tag[nd][1],tag[nd][2]); tag[nd][0]=tag[nd][1]=tag[nd][2]=0; } void change(int nd,int l,int r,int x,int y,int a0,int a1,int a2) { if(l>y||r<x) return ; if(x>y) return ; if(l>=x&&r<=y) return add(nd,l,r,a0,a1,a2); int mid=l+r>>1; pushdown(nd,l,r); change(nd<<1,l,mid,x,y,a0,a1,a2); change(nd<<1|1,mid+1,r,x,y,a0,a1,a2); pushup(nd); } node query(int nd,int l,int r,int x,int y) { if(l>y||r<x) return {0,0,0}; if(l>=x&&r<=y) return {tr[nd][0],tr[nd][1],tr[nd][2]}; int mid=l+r>>1; pushdown(nd,l,r); return query(nd<<1,l,mid,x,y)+query(nd<<1|1,mid+1,r,x,y); } int ask(int nd,int l,int r,int p) { if(l==r) { if(tr[nd][0]) return 0; if(tr[nd][1]) return 1; if(tr[nd][2]) return 2; } int mid=l+r>>1; pushdown(nd,l,r); if(l<=p&&p<=mid) return ask(nd<<1,l,mid,p); else return ask(nd<<1|1,mid+1,r,p); } int check(int x) { memset(tr,0,sizeof(tr)); memset(tag,0,sizeof(tag)); for(int i=1;i<=n;i++) { if(a[i]<x) change(1,1,n,i,i,1,0,0); if(a[i]==x) change(1,1,n,i,i,0,0,1); if(a[i]>x) change(1,1,n,i,i,0,1,0); } for(int i=1;i<=m;i++) { node num=query(1,1,n,ql[i],qr[i]); if(qt[i]==0) { change(1,1,n,ql[i],ql[i]+num.a0-1,1,0,0); change(1,1,n,ql[i]+num.a0,ql[i]+num.a0+num.a2-1,0,0,1); change(1,1,n,ql[i]+num.a0+num.a2,qr[i],0,1,0); } else { change(1,1,n,ql[i],ql[i]+num.a1-1,0,1,0); change(1,1,n,ql[i]+num.a1,ql[i]+num.a1+num.a2-1,0,0,1); change(1,1,n,ql[i]+num.a1+num.a2,qr[i],1,0,0); } } return ask(1,1,n,q); } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); cin>>n>>m; for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=m;i++) { qt[i]=read(); ql[i]=read(); qr[i]=read(); } cin>>q; int l=1,r=n; while(l<=r) { int mid=l+r>>1; int k=check(mid); if(k==1) l=mid+1; if(k==2) {cout<<mid; return 0;} if(k==0) r=mid-1; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效