[题解]luogu_P2824_HEOI2016排序(线段树/二分

Posted superminivan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[题解]luogu_P2824_HEOI2016排序(线段树/二分相关的知识,希望对你有一定的参考价值。

很难想,首先要二分答案,这样对于所有大于mid的数可以当做1,所有小于mid的可以当做0,这些1或0内部怎么排其实无所谓,然后1全放一边就可以,单调性的话比较好说,因为p点的数要么比mid大要么小,排列答案只会有一个

#include<bits/stdc++.h>
#define ls (x<<1)
#define rs (x<<1|1)
#define mid ((l+r)>>1)
using namespace std;
const int maxn=100009;
int n,m,a[maxn],p,L[maxn],R[maxn],ch[maxn];
struct node{
    int sum,tg;
}t[maxn<<2];
inline void upd(int x){
    t[x].sum=t[ls].sum+t[rs].sum;
}
inline void pd(int x,int l,int r){
    if(t[x].tg){
        t[ls].tg=t[x].tg;
        t[rs].tg=t[x].tg;
        if(t[x].tg==1){t[ls].sum=(mid-l+1);t[rs].sum=(r-mid);}
        else t[ls].sum=t[rs].sum=0;
        t[x].tg=0;
    }
}
void build(int x,int l,int r,int md){
    if(l==r){
        t[x].sum=(a[l]>=md);t[x].tg=0;
        return ;
    }
    build(ls,l,mid,md);build(rs,mid+1,r,md);
    upd(x);t[x].tg=0;
}
void change(int x,int l,int r,int L,int R,int val){
    if(L<=l&&r<=R){
        t[x].sum=val*(r-l+1);
        t[x].tg=val?1:-1;
        return;
    }
    pd(x,l,r);
    if(L<=mid)change(ls,l,mid,L,R,val);
    if(R>mid)change(rs,mid+1,r,L,R,val);
    upd(x);
}
int query(int x,int l,int r,int L,int R){
    if(L<=l&&r<=R)return t[x].sum;
    pd(x,l,r);
    int ans=0;
    if(L<=mid)ans+=query(ls,l,mid,L,R);
    if(R>mid)ans+=query(rs,mid+1,r,L,R);
    return ans;
}
int queryp(int x,int l,int r,int pos){
    if(l==r)return t[x].sum;
    pd(x,l,r);
    if(pos<=mid)return queryp(ls,l,mid,pos);
    else return queryp(rs,mid+1,r,pos);
}
bool check(int md){
    build(1,1,n,md);
    for(int i=1;i<=m;i++){
        int cnt1=query(1,1,n,L[i],R[i]);
        if(cnt1==0)continue;
        if(ch[i]==0){
            change(1,1,n,R[i]-cnt1+1,R[i],1);
            change(1,1,n,L[i],R[i]-cnt1,0);
        }
        else{
            change(1,1,n,L[i],L[i]+cnt1-1,1);
            change(1,1,n,L[i]+cnt1,R[i],0);
        }
    }
    return queryp(1,1,n,p);
}
int main(){
//    freopen("4.in","r",stdin);
    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",&ch[i],&L[i],&R[i]);
    scanf("%d",&p);
    int LL=1,RR=n,ans;
    while(LL<=RR){
        int midd=(LL+RR)>>1;
        if(check(midd))ans=midd,LL=midd+1;
        else RR=midd-1;
    }
    printf("%d",ans);
}

 

以上是关于[题解]luogu_P2824_HEOI2016排序(线段树/二分的主要内容,如果未能解决你的问题,请参考以下文章

LGP2824[HEOI2016/TJOI2016]排序

线段树好题! P2824 [HEOI2016/TJOI2016]排序 题解

BZOJ4552:[HEOI2016/TJOI2016]排序——题解

luogu P2824排序题解

「Luogu2824」[HEOI2016/TJOI2016]排序

Luogu P2824 [HEOI2016/TJOI2016]排序