[Tjoi2016&Heoi2016]排序

题目

bzoj4552

题解

二分q位置上的值mid,然后将所有大于mid的数记为1,小于等于mid的数记为0,用线段树维护区间的和

对于升序排列,及时将所有为1的数放在右边;降序排列就是将所有为0的数放在右边

最后判断出p位置为1还是0,若为1,则说明mid小于真实值,l=mid+1;若为0,则mid可能大于真实值(注意是可能),记录ans并r=mid

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath> 
#define N 1000000
using namespace std;
 
int n,m,a[N],q;
int opt[N],cl[N],cr[N];
 
struct node{int l,r,sum,d;}T[N];
 
void pushup(int p){T[p].sum=T[p<<1].sum+T[p<<1|1].sum;}
void pushdown(int p)
{
    if(T[p].d==-1) return;
    T[p<<1].sum=(T[p<<1].r-T[p<<1].l+1)*T[p].d;
    T[p<<1|1].sum=(T[p<<1|1].r-T[p<<1|1].l+1)*T[p].d;
    T[p<<1].d=T[p<<1|1].d=T[p].d;
    T[p].d=-1;
}
 
void build(int p,int x,int y,int v)
{
    T[p].l=x;T[p].r=y;T[p].d=-1;
    if(x==y) {T[p].sum=(a[x]>v);return;}
    if(x<y)
    {
        int mid=(x+y)>>1;
        build(p<<1,x,mid,v);
        build(p<<1|1,mid+1,y,v);
        pushup(p);
    }
}
 
int query(int p,int x,int y)
{
    int pl=T[p].l,pr=T[p].r;
    if(pl==x&&pr==y) return T[p].sum;
    pushdown(p);
    int mid=(pl+pr)>>1;
    if(y<=mid) return query(p<<1,x,y);
    else if(x>mid) return query(p<<1|1,x,y);
    else return query(p<<1,x,mid)+query(p<<1|1,mid+1,y);
}
 
void set(int p,int x,int y,int v)
{
    int pl=T[p].l,pr=T[p].r;
    if(pl==x&&pr==y)
    {
        T[p].sum=(T[p].r-T[p].l+1)*v;
        T[p].d=v;
        return;
    } 
    pushdown(p);
    int mid=(pl+pr)>>1;
    if(y<=mid) set(p<<1,x,y,v);
    else if(x>mid) set(p<<1|1,x,y,v);
    else
    {
        set(p<<1,x,mid,v);
        set(p<<1|1,mid+1,y,v);
    }
    pushup(p);//
}
 
bool check(int x)
{
    build(1,1,n,x);//建树
    for(int i=1;i<=m;i++)
    {
        int sum=query(1,cl[i],cr[i]);//先求出区间内大于x的个数 
        if(!opt[i])//升序 
        {
            if(sum) set(1,cr[i]-sum+1,cr[i],1);//将1全部放右边
            if(cr[i]-sum>=cl[i]) set(1,cl[i],cr[i]-sum,0); 
        }
        else//降序 
        {
            if(sum) set(1,cl[i],cl[i]+sum-1,1);//将1全部放左边
            if(cl[i]+sum<=cr[i]) set(1,cl[i]+sum,cr[i],0);           
        }
    }
    return query(1,q,q)==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",&opt[i],&cl[i],&cr[i]);
    scanf("%d",&q);
    int l=1,r=n,mid,ans;
    while(l<r)//二分p位置上的值 
    {
        mid=(l+r)>>1;
        if(check(mid)) ans=mid,r=mid;
        else l=mid+1;
    }
    printf("%d",ans);
    return 0;
}
posted @ 2017-10-06 13:33  XYZinc  阅读(207)  评论(0编辑  收藏  举报