3130 排序

Task
给出1-n的全排列,m次操作分为两种:
① (0,l,r)将区间[l,r]升序排列
② (1,l,r)将区间[l,r]降序排列。
n,m<=1e5

Solution
6秒的时限,真是个暴力的好时机
用sort函数sort(A+l,A+r+1,cmp)可以对区间[l,r]升序或者降序排列,这样就有80分了。
但是本人粗鄙,写成了sort(A+l+1,A+r+1),居然还有60分
想到平时的sort都是(A,A+n)或(A+1,A+n+1),分别是左端点,右端点+1的位置。

“二分是一个方向”
二分的好处:把求知问题转化为判定问题。
类似的题目:区间第k值,中位数。

二分x,判定解是否大于等于x.按照x,记大于等于x的数为1,小于x的数为0。对于m次操作后,如果id位上的数为1,判定为可行。

问题转化为,一个01序列,m次操作后,第id位上的数是否为1。
①因为一个区间只有01,无论是升序降序,都有1个0和1的分界点。因为区间的长度是一定的,对区间求和,可以找到1的个数。
②按照分界线前部分为c,后部分为c^1.(c为0或1).

区间求和,区间更新,可以用延迟更新的线段树完成。

const int M=1e5+3;
int A[M];
int n,m,pos;
struct node1{
    int cnt[2],l,r,f;
    inline void clear(){
        memset(cnt,0,sizeof(cnt));
    }
}res;
struct node2{
    int a,l,r;
}Q[M];
struct Segment_Tree{
    node1 t[M<<2];
    inline void up(int p){
        rep(i,0,1)
            t[p].cnt[i]=t[lsn(p)].cnt[i]+t[rsn(p)].cnt[i];
    }
    inline void down(int p){
        if(t[p].f==-1)return;
        int c=t[p].f,l=lsn(p),r=rsn(p);
        t[l].f=t[r].f=c;
        t[l].cnt[c]=t[l].r-t[l].l+1;
        t[r].cnt[c]=t[r].r-t[r].l+1;
        t[l].cnt[c^1]=t[r].cnt[c^1]=0;
        t[p].f=-1;
    }
    inline void build(int l,int r,int x,int p){
        t[p].l=l,t[p].r=r;t[p].f=-1;
        if(l==r){
            bool a=(A[l]>=x);
            t[p].cnt[a]=1;t[p].cnt[a^1]=0;
            return;
        }
        int mid=l+r>>1;
        build(l,mid,x,lsn(p));
        build(mid+1,r,x,rsn(p));
        up(p);
    }
    inline void query(int L,int R,int l,int r,int p){
        if(l==L&&r==R){
            rep(i,0,1)res.cnt[i]+=t[p].cnt[i];
            return;
        }
        down(p);
        int mid=L+R>>1;
        if(r<=mid)query(L,mid,l,r,lsn(p));
        else if(l>mid)query(mid+1,R,l,r,rsn(p));
        else{
            query(L,mid,l,mid,lsn(p));
            query(mid+1,R,mid+1,r,rsn(p));
        }
    }
    inline void update(int L,int R,int l,int r,int c,int p){//区间刷成c颜色 
        if(l==L&&r==R){
            t[p].cnt[c]=r-l+1;
            t[p].cnt[c^1]=0;
            t[p].f=c;
            return;
        }
        down(p);
        int mid=L+R>>1;
        if(r<=mid)update(L,mid,l,r,c,lsn(p));
        else if(l>mid)update(mid+1,R,l,r,c,rsn(p));
        else{
            update(L,mid,l,mid,c,lsn(p));
            update(mid+1,R,mid+1,r,c,rsn(p));
        }
        up(p);
    }
}T;
struct P100{
    inline void input(){
        rd(n);rd(m);
        rep(i,1,n)rd(A[i]);
        rep(i,1,m){
            rd(Q[i].a);rd(Q[i].l);rd(Q[i].r);
        }
        rd(pos);
    }
    inline bool check(int x){//解是否>=x 
        int a,l,r;
        T.build(1,n,x,1);
        rep(i,1,m){
            res.clear();
            a=Q[i].a,l=Q[i].l,r=Q[i].r;
            T.query(1,n,l,r,1);
            if(min(res.cnt[0],res.cnt[1])==0)continue;//这个区间都是0或1 
            T.update(1,n,l,l+res.cnt[a]-1,a,1);//区间刷成颜色a
            T.update(1,n,l+res.cnt[a],r,a^1,1);//区间刷成颜色a^1 
        }
        res.clear();
        T.query(1,n,pos,pos,1);
        return res.cnt[1]==1;

    }
    inline void solve(){
        input();
        int l=1,r=n,mid,ans;
        while(l<=r){
            mid=l+r>>1;
            if(check(mid)){l=mid+1;ans=mid;}
            else r=mid-1;
        }
        sc(ans);
    }
}P100;
int main(){
    P100.solve();
    return 0;
}

你可能感兴趣的:(二分答案)