P2824 [HEOI2016/TJOI2016] 排序
今天就写了这一题线段树+二分,qwq
我感觉这题主要难点在于将普通序列的排序转换成用01序列排序,用线段树维护01序列。
最后只询问第q位上的数,这个数是全排列中的数,有单调性,所以可以用二分答案,将大于等于mid的设为1,小于mid的设为0。
在进行m将排序后,如果第q位为1,则在[mid,r]中查找,如果第q位为0,则在[l,mid)中查找
#include<bits/stdc++.h>
#define ls id<<1
#define rs id<<1|1
using namespace std;
const int N=1e6;
int a[N],L[N],R[N];
int n,m;
int op[N];
int q;
struct tree{
int l,r;
int sum,tag;
}tr[N<<1];
void pushup(int id){
tr[id].sum=tr[ls].sum+tr[rs].sum;
}
void pushdown(int id){
if(tr[id].tag==-1)return ;
tr[ls].sum=tr[id].tag*(tr[ls].r-tr[ls].l+1);
tr[rs].sum=tr[id].tag*(tr[rs].r-tr[rs].l+1);
tr[ls].tag=tr[rs].tag=tr[id].tag;
tr[id].tag=-1;
}
void build(int id,int l,int r,int x){
tr[id]={l,r,a[l]>=x,-1};
if(l==r)return ;
int mid=(l+r)>>1;
build(ls,l,mid,x);
build(rs,mid+1,r,x);
pushup(id);
}
void mod(int id,int l,int r,int x){
if(l>tr[id].r||r<tr[id].l)return ;
if(l<=tr[id].l&&tr[id].r<=r){
tr[id].sum=x*(tr[id].r-tr[id].l+1);
tr[id].tag=x;
return ;
}
pushdown(id);
mod(ls,l,r,x);
mod(rs,l,r,x);
pushup(id);
}
int query(int id,int l,int r){
if(l>tr[id].r||r<tr[id].l)return 0;
if(l<=tr[id].l&&tr[id].r<=r)return tr[id].sum;
pushdown(id);
return query(ls,l,r)+query(rs,l,r);
}
int check(int x){
build(1,1,n,x);
for(int i=1;i<=m;i++){
int l=L[i],r=R[i];
int cnt=query(1,l,r);
if(op[i]==0){
mod(1,l,r-cnt,0);
mod(1,r-cnt+1,r,1);
}
else{
mod(1,l,l+cnt-1,1);
mod(1,l+cnt,r,0);
}
}
return query(1,q,q);
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=m;i++)
cin>>op[i]>>L[i]>>R[i];
cin>>q;
int l=0,r=n+1,ans(0);
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)){
ans=mid;
l=mid+1;
}
else r=mid-1;
}
cout<<ans<<endl;
return 0;
}