【Luogu】P2824排序(二分答案+线段树排序)

  题目链接

  震惊!两个线段树和一个线段树竟是50分的差距!

  本题可以使用二分答案,二分那个位置上最后是什么数。怎么验证呢?

  把原序列改变,大于等于mid的全部变成1,小于mid的全部变成0,之后线段树排序。

  最后看那个位置上是1还是0,若是1则说明最后那个位置上是个>=mid的数。

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#define left (rt<<1)
#define right (rt<<1|1)
#define mid ((l+r)>>1)
#define lson l,mid,left
#define rson mid+1,r,right
#define maxn 300030
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

struct Que{
    int opt,from,to;
}q[maxn];

int d[maxn],w[maxn];

int tree[maxn*4],mem[maxn*4],tag[maxn*4];
inline void pushup(int rt){    tree[rt]=tree[left]+tree[right];    }
inline void build(int l,int r,int rt){
    tree[rt]=mem[rt]=tag[rt]=0;
    if(l==r){
        tree[rt]=w[l];
        //printf("%d %d\n",l,w[l]);
        return;
    }
    build(lson);
    build(rson);
    pushup(rt);
}
inline void pushdown(int rt,int m){
    if(mem[rt]==0&&tag[rt]==0)    return;
    if(mem[rt]){
        mem[left]=mem[right]=1;
        tree[left]=tree[right]=0;
        tag[left]=tag[right]=0;
        mem[rt]=0;
    }
    if(tag[rt]){
        tag[left]+=tag[rt];    tag[right]+=tag[rt];
        tree[left]+=m-(m>>1);
        tree[right]+=m>>1;
        tag[rt]=0;
    }
    return;
}
void update(int from,int to,int l,int r,int rt){
    if(from<=l&&to>=r){
        tag[rt]++;
        tree[rt]+=r-l+1;
        return;
    }
    pushdown(rt,r-l+1);
    if(from<=mid)    update(from,to,lson);
    if(to>mid)        update(from,to,rson);
    pushup(rt);
}
void memdate(int from,int to,int l,int r,int rt){
    if(from<=l&&to>=r){
        tag[rt]=0;    mem[rt]=1;
        tree[rt]=0;
        return;
    }
    pushdown(rt,r-l+1);
    if(from<=mid)    memdate(from,to,lson);
    if(to>mid)        memdate(from,to,rson);
    pushup(rt);
}
int query(int from,int to,int l,int r,int rt){
    if(from<=l&&to>=r)    return tree[rt];
    pushdown(rt,r-l+1);
    int ans=0;
    if(from<=mid)    ans+=query(from,to,lson);
    if(to>mid)        ans+=query(from,to,rson);
    return ans;
}


bool check(int lim,int n,int m,int last){
    build(1,n,1);
    for(int i=1;i<=m;++i){
        int opt=q[i].opt,from=q[i].from,to=q[i].to;
        int c1=query(from,to,1,n,1);
        int c2=to-from+1-c1;
        //printf("%d %d<<\n",c1,c2);
        memdate(from,to,1,n,1);
        if(opt==0)    update(from+c2,to,1,n,1);
        else    update(from,from+c1-1,1,n,1);
    }
    //printf("zero\n");
    //for(int i=1;i<=n;++i)    printf("%d ",zero.query(i,i,1,n,1));
    //printf("\none\n");
    //for(int i=1;i<=n;++i)    printf("%d ",one.query(i,i,1,n,1));
    //printf("\n");
    return query(last,last,1,n,1);
}

int main(){
    int n=read(),m=read();
    for(int i=1;i<=n;++i)    d[i]=read();
    for(int i=1;i<=m;++i)    q[i]=(Que){read(),read(),read()};
    int last=read();
    int l=1,r=n,ans=0;
    while(l<=r){
        //printf("%d %d %d\n",l,r,mid);
        for(int i=1;i<=n;++i)
            if(d[i]>=mid)    w[i]=1;
            else             w[i]=0;
        //for(int i=1;i<=n;++i)    printf("%d<",w[i]);
        //printf("\n");
        if(check(mid,n,m,last)){
            ans=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    printf("%d",ans);
    return 0;
}

 

posted @ 2018-04-16 14:35  Konoset  阅读(228)  评论(0编辑  收藏  举报