zoukankan      html  css  js  c++  java
  • 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
    ",ans);  
        return 0; 
    }
    

      

  • 相关阅读:
    图与图算法在实际中的应用
    python Tricks —— list 镜像复制与 list comprehension 列表解析的顺序
    C语言高速入门系列(五)
    Linked List Cycle
    poj 2689 Prime Distance(大区间筛素数)
    三层结构——理论篇
    史上最简单的Hibernate入门简单介绍
    [SQL]远程使用PostgreSQL Studio可视化查看PostgreSQL数据库
    MySQL建立双向主备复制server配置方法
    win2003的IIS無法使用,又一次安裝提示找不到iisadmin.mfl文件
  • 原文地址:https://www.cnblogs.com/guangheli/p/13237565.html
Copyright © 2011-2022 走看看