BZOJ 4552: [Tjoi2016&Heoi2016]排序 [二分][線段樹]

題意:
給定一個數列{an },然後進行m 次操作,每次操作是對一個區間進行升序或降序排序,要求所有操作後位置q 上的數

解題報告:
不會樹套樹,只能膜線段樹題解
二分最終的答案x ,將原數列中小於x 的數變成0,大於等於的變成1
那麼每次驗證的時候我們只要得出最後的01序列然後看第q 上是不是1
這具有單調性所以可以二分
怎麼得到最終數列呢?對於上述我們的驗證方法,所有0之間與所有1之間是沒有區別的
所以每次排序我們只要按照操作將0放在區間的一邊,將1放在另一邊,這可以用線段樹輕鬆解決

可以將有序的數據轉化爲無序的來簡化問題

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 100005
#define ls (x<<1)
#define rs (x<<1|1)
#define mid (l+r>>1)
using namespace std;

inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline int read(){
    int a=0;char f=1,c=nc();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();}
    while(c>='0'&&c<='9'){a=a*10+c-'0';c=nc();}
    return a*f;
}

struct xw{
    int opt,l,r;
}q[N];
int n,m,pos,a[N],sum[N<<2],lzy[N<<2];

void update(int x,int l,int r){if(l!=r) sum[x]=sum[ls]+sum[rs];}

void build(int x,int l,int r,int v){
    lzy[x]=-1;
    if(l==r){
        sum[x]=(a[l]>=v);
        return;
    }
    build(ls,l,mid,v),build(rs,mid+1,r,v);
    update(x,l,r);
    return;
}

void push(int x,int l,int r){
    if(l==r) return;
    if(lzy[x]!=-1){
        int t=lzy[x];lzy[x]=-1;
        sum[ls]=(mid-l+1)*t,sum[rs]=(r-mid)*t,lzy[ls]=lzy[rs]=t;
    }
}

int query(int x,int l,int r,int ql,int qr){
    if(l>=ql&&r<=qr) return sum[x];
    push(x,l,r);
    int res=0;
    if(ql<=mid) res+=query(ls,l,mid,ql,qr);
    if(qr>mid) res+=query(rs,mid+1,r,ql,qr);
    update(x,l,r);
    return res;
}

void change(int x,int l,int r,int ql,int qr,int v){
    if(l>=ql&&r<=qr){
        sum[x]=(r-l+1)*v;
        lzy[x]=v;
        return;
    }
    push(x,l,r);
    if(ql<=mid) change(ls,l,mid,ql,qr,v);
    if(qr>mid) change(rs,mid+1,r,ql,qr,v);
    update(x,l,r);
    return;
}

void print(){for(int i=1;i<=n;++i) printf("%d%s",query(1,1,n,i,i),i==n?"\n":" ");}

bool check(int x){
    build(1,1,n,x);
//  print();
    for(int i=1;i<=m;++i){
        int num1=query(1,1,n,q[i].l,q[i].r);
        int num0=q[i].r-q[i].l+1-num1;
        if(!q[i].opt){
            if(num0) change(1,1,n,q[i].l,q[i].l+num0-1,0);
            if(num1) change(1,1,n,q[i].r-num1+1,q[i].r,1);
        }
        else{
            if(num1) change(1,1,n,q[i].l,q[i].l+num1-1,1);
            if(num0) change(1,1,n,q[i].r-num0+1,q[i].r,0);
        }
    }
//  print();
    return query(1,1,n,pos,pos);
}

int main(){
    n=read(),m=read();
    for(int i=1;i<=n;++i) a[i]=read();
    for(int i=1;i<=m;++i) q[i].opt=read(),q[i].l=read(),q[i].r=read();
    int l=1,r=n,ans=N;
    pos=read();
    while(l<=r){
        if(check(mid)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    printf("%d\n",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章