[HEOI2016/TJOI2016]排序 解题报告
题意
给出一个大小为 \(n\) 的排列, 对这个排列进行 \(m\) 次操作, 操作分为以下两种,
0 l r
表示将区间 \([l,r]\) 的数升序排序.1 l r
表示将区间 \([l,r]\) 的数降序排序.
询问 \(m\) 次操作后下标为 \(q\) 的数字.
思路
不看题解打死也想不出来系列
考虑二分答案.
设当前二分的答案为 \(mid\), 把原排列中 大于等于 \(mid\) 的数标记为 \(1\), 小于 \(mid\) 的数标记为 \(0\).
对于这样的一个 \(0,1\) 串, 我们可以用线段树实现 \(\log n\) 的排序.
若当前区间 \(l,r\) 的区间和为 \(num\), 那么就代表有 \(num\) 个 \(1\) 和 \(r-l+1-num\) 个 \(0\), 然后我们只需按要求把区间的前部分设为 \(0\) 或 \(1\), 后部分设为另一个数就行了.
最后判断一下下标为 \(q\) 的数字是否为 \(1\), 若是, 则另 \(l=mid+1\), 否则另 \(r=mid-1\).
代码
#include<bits/stdc++.h>
using namespace std;
const int _=1e5+7;
const int __=4e5+7;
int n,m,q,a[_],sum[__],tag[__],ans,x;
struct oper{
int l,r,ty;
}op[_];
void init(){
cin>>n>>m;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&op[i].ty,&op[i].l,&op[i].r);
cin>>q;
}
void build(int k,int l,int r){
tag[k]=-1;
if(l==r){ sum[k]= a[l]>=x; return; }
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
sum[k]=sum[k<<1]+sum[k<<1|1];
}
void upd(int k,int l,int r,bool w){
sum[k]= w ?r-l+1 :0;
tag[k]=w;
}
void psd(int k,int l,int r){
if(tag[k]==-1) return;
int mid=(l+r)>>1;
upd(k<<1,l,mid,tag[k]);
upd(k<<1|1,mid+1,r,tag[k]);
tag[k]=-1;
}
void modify(int k,int l,int r,int x,int y,bool w){
if(x>y) return;
if(l>=x&&r<=y){ upd(k,l,r,w); return; }
psd(k,l,r);
int mid=(l+r)>>1;
if(x<=mid) modify(k<<1,l,mid,x,y,w);
if(y>mid) modify(k<<1|1,mid+1,r,x,y,w);
sum[k]=sum[k<<1]+sum[k<<1|1];
}
int query(int k,int l,int r,int x,int y){
if(l>=x&&r<=y) return sum[k];
psd(k,l,r);
int mid=(l+r)>>1,res=0;
if(x<=mid) res+=query(k<<1,l,mid,x,y);
if(y>mid) res+=query(k<<1|1,mid+1,r,x,y);
return res;
}
bool judge(int mid){
x=mid;
build(1,1,n);
for(int i=1;i<=m;i++){
int num=query(1,1,n,op[i].l,op[i].r);
if(!op[i].ty){
modify(1,1,n,op[i].l,op[i].r-num,0);
modify(1,1,n,op[i].r-num+1,op[i].r,1);
}
else{
modify(1,1,n,op[i].l,op[i].l+num-1,1);
modify(1,1,n,op[i].l+num,op[i].r,0);
}
}
return query(1,1,n,q,q);
}
void run(){
int l=1,r=n;
while(l<=r){
int mid=(l+r)>>1;
if(judge(mid)){ ans=mid; l=mid+1; }
else r=mid-1;
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("x.in","r",stdin);
freopen("x.out","w",stdout);
#endif
init();
run();
printf("%d\n",ans);
}