luoguP2824 [HEOI2016/TJOI2016]排序 二分+线段树

题意:给定一个排列,每次有两种操作:1 区间降序排列 2 区间升序排列,求 m 才操作后 q 位置上的数字

这道题非常神仙啊.    

假如说序列中只有 0,1 的话我们只需要用线段树维护 0,1的个数然后进行区间覆盖即可.     

由于所有数互不相同,考虑二分 $q$ 点上的数 $mid$,然后将大于等于 $mid$ 的设置成 $1$,小于的设置成 $0$.    

然后我们对新构建的序列从头到尾操作一下,发现如果 $q$ 位置是 $1$ 的话答案要大于等于 $mid$,反之亦然.       

那么这个 $q$ 点的答案就满足单调性了,可以二分.   

总时间复杂度为 $O(n \log^2 n)$   

code: 

#include <bits/stdc++.h>     
#define N 100009    
#define lson now<<1
#define rson now<<1|1
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;       
int n,as,m; 
int a[N],b[N];  
int c[2][N<<2],t[2][N<<2],len[N<<2];  
struct data {  
    int l,r,op;
}p[N];     
void pushup(int now)  {  
    c[0][now]=c[0][lson]+c[0][rson];  
    c[1][now]=c[1][lson]+c[1][rson];   
}   
void mark(int now,int v) {    
    t[v][now]=1,t[v^1][now]=0;       
    c[v][now]=len[now],c[v^1][now]=0;    
}
void pushdown(int now) {  
    if(t[0][now]) mark(lson,0),mark(rson,0),t[0][now]=0;  
    if(t[1][now]) mark(lson,1),mark(rson,1),t[1][now]=0;       
}
void build(int l,int r,int now) {    
    c[0][now]=c[1][now]=0; 
    t[0][now]=t[1][now]=0;  
    len[now]=r-l+1;   
    if(l==r) {     
        c[b[l]][now]=1;  
        return;  
    }  
    int mid=(l+r)>>1;  
    build(l,mid,lson),build(mid+1,r,rson); 
    pushup(now); 
}
int query(int l,int r,int now,int L,int R,int v) {  
    if(l>=L&&r<=R) return c[v][now];  
    int mid=(l+r)>>1,re=0; 
    pushdown(now);  
    if(L<=mid)  re+=query(l,mid,lson,L,R,v);  
    if(R>mid)   re+=query(mid+1,r,rson,L,R,v);  
    return re;   
}
void upd(int l,int r,int now,int L,int R,int v) {   
    if(l>=L&&r<=R) { mark(now,v); return; }  
    int mid=(l+r)>>1;  
    pushdown(now);  
    if(L<=mid)   upd(l,mid,lson,L,R,v);  
    if(R>mid)    upd(mid+1,r,rson,L,R,v);      
    pushup(now);   
}
int check(int tmp) {        
    for(int i=1;i<=n;++i) b[i]=(a[i]>=tmp);   
    build(1,n,1);    
    int l,r,op,x,y,z;  
    for(int i=1;i<=m;++i) {   
        l=p[i].l,r=p[i].r,op=p[i].op;  
        if(op==0) {  
            x=query(1,n,1,l,r,0);  
            y=query(1,n,1,l,r,1);        
            if(x) upd(1,n,1,l,l+x-1,0);   
            if(y) upd(1,n,1,r-y+1,r,1);    
        } 
        else { 
            x=query(1,n,1,l,r,0);  
            y=query(1,n,1,l,r,1);  
            if(y) upd(1,n,1,l,l+y-1,1);   
            if(x) upd(1,n,1,r-x+1,r,0);   
        }
    }
    return query(1,n,1,as,as,1);     
}
int main() {  
    // setIO("input");     
    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",&p[i].op,&p[i].l,&p[i].r);          
    }    
    scanf("%d",&as);   
    int l=1,r=n,ans=0,mid; 
    while(l<=r) {  
        mid=(l+r)>>1;  
        if(check(mid))  ans=mid,l=mid+1;  
        else r=mid-1;        
    }
    printf("%d\n",ans);  
    return 0; 
}

  

posted @ 2020-07-05 08:11  EM-LGH  阅读(137)  评论(0编辑  收藏  举报