P2824 [HEOI2016/TJOI2016]排序

链接:Miku

----------------------------

一道二分+线段树

-----------------------------

显然暴力模拟会T飞,可以用二分解决

-----------------------------

二分啥呢?二分mid与最后在q的位置的数的大小

但是怎么知道大还是小呢,既然我们只想要知道大还是小,那么那个点原来是

多大/多小是没有意义的,只有和mid的相对大小,那么我们就把比mid大的改成1,小于等于的改为0

然后进行排序

这样仅仅是不行的,对于排序,因为已经变成了0和1,那么我们只要知道区间1的个数就行了,然后把1都放到最前面/最后面即可

这个查询和修改可以用线段树来实现

----------------------------------

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
int m;
int l,r;
int mid;
int a[100005];
int b[100005];
int sum[400005];
int lazy[400005];
int q;
int f;
struct ch{
    int l;
    int r;
    int f;
}change[100005];
void pushup(int x){
    sum[x]=sum[x<<1]+sum[x<<1|1];
}
void pushdown(int x,int l,int r){
    if(lazy[x]!=-1){
        int mid=(l+r)>>1;
        lazy[x<<1]=lazy[x];
        lazy[x<<1|1]=lazy[x];
        sum[x<<1]=lazy[x]*(mid-l+1);
        sum[x<<1|1]=lazy[x]*(r-mid);
        lazy[x]=-1;
        return ;
    }
    return ;
}
void update(int x,int l,int r,int L,int R,int d){
    if (L > R) return;
    if(L<=l&&r<=R){
        sum[x]=d*(r-l+1);
        lazy[x]=d;
        return ;
    }
    pushdown(x,l,r);
    int mid=(l+r)>>1;
    if(L<=mid) update(x<<1,l,mid,L,R,d);
    if(R>mid)  update(x<<1|1,mid+1,r,L,R,d);
    pushup(x); 
}
int query(int x,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        return sum[x];
    }
    pushdown(x,l,r);
    int mid=(l+r)>>1;
    int ans=0;
    if(L<=mid) ans+=query(x<<1,l,mid,L,R);
    if(R>mid) ans+=query(x<<1|1,mid+1,r,L,R);
    return ans;
}
bool check(int k){
    for(int i=1;i<=4*n;++i){//每一次都要初始化 
    lazy[i]=-1;
    sum[i]=0;
    }
    for(int i=1;i<=n;++i){
        if(a[i]>=k){
            update(1,1,n,i,i,1);//初始化 
        }
    }
    for(int i=1;i<=m;++i){
        if(change[i].f==0){
            int cnt=query(1,1,n,change[i].l,change[i].r);//只有0,1的排序 
            update(1,1,n,change[i].r-cnt+1,change[i].r,1);
            update(1,1,n,change[i].l,change[i].r-cnt,0);
        }
        else{
            int cnt=query(1,1,n,change[i].l,change[i].r);
            update(1,1,n,change[i].l+cnt,change[i].r,0);
            update(1,1,n,change[i].l,change[i].l+cnt-1,1);
        }
    }
    if(query(1,1,n,q,q)){//查询一下大了还是小了 
        return 1;
    }
    return 0;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=m;++i){
        scanf("%d%d%d",&change[i].f,&change[i].l,&change[i].r);
    }
    scanf("%d",&q);
    l=1;//l永远成立 
    r=n+1;//r永不成立 
    while(r-l>1){//当然要小于1最后 
        mid=(l+r)>>1;
        if(check(mid)){
            l = mid;
        }
        else{
            r =  mid;
        }
    }
    cout<<l;
    return 0;
}
Ac

 

posted @ 2020-02-29 18:11  Simex  阅读(163)  评论(0编辑  收藏  举报