• 洛谷 P2824 [HEOI2016/TJOI2016]排序


    题目链接

    本题采用线段树,将排序的操作巧妙转化为0/1序列的区间覆盖问题

    首先我们先二分最终答案(ans)

    之所以答案有单调性,是因为我们进行了如下转换

    1. 将原序列(A)变为0/1序列(A'),若(a_i < ans)(a'_i = 0) 否则 (a'_i = 1),z这样我们就得到了0/1序列(A')

    2. 将操作转换为区间覆盖: 设操作区间为([l,r]),操作符为(opt),首先统计区间(1)的个数,若为升序排序,则区间([l,r-x])覆盖为(0),区间([r-x+1,r])覆盖为(1);若为降序排序,则区间([l,l+x-1])覆盖为(1),区间([l+x,r])覆盖为(0). 这样排序本质上只是把两类不同的数区分开来,并不是真正的排序,因此复杂度优秀.

    3.操作结束后,查询(pos)位的值((pos)即为题目要求查询的位置),是(0)还是(1).若为(0),说明(ans)过大,返回(r=mid-1),否则返回(ans=mid,l=mid+1)

    答案的单调性,是因为原序列一定,操作一定,所以(pos)位上最终的数是确定唯一的,这个数同时又在([1,n])的区间内,因此可以二分答案,并用以上转化进行(check)

    #include <bits/stdc++.h>
    using namespace std;
    #define mid ((l+r)>>1)
    #define ls (nod<<1)
    #define rs (nod<<1|1)
    #define lson ls,l,mid
    #define rson rs,mid+1,r
    
    int read(){
    	int x=0; char c; int flag=1;
    	for(c=getchar();!isdigit(c);c=getchar()) if(c=='-') flag=-1;
    	for(;isdigit(c);c=getchar()) x=((x+(x<<2))<<1)+(c^48);
    	return x*flag;
    }
    
    const int N=1e5+10;
    
    int n,m,pos;
    int a[N];
    struct operation{
        int opt,l,r;
    }b[N];
    
    struct node{
        int l,r,len;
        int s[2];
        int tag;
    }t[N<<2];
    
    void pushup(int nod){
        for(int i=0;i<=1;i++) t[nod].s[i]=t[ls].s[i]+t[rs].s[i];
    }
    
    void pushdown(int nod){
        if(t[nod].tag==-1) return ;
        int v=t[nod].tag; t[nod].tag=-1;
        
        t[ls].s[v]=t[ls].len; t[ls].s[1-v]=0;
        t[rs].s[v]=t[rs].len; t[rs].s[1-v]=0;
        t[ls].tag=t[rs].tag=v;
    }
    
    void build(int nod,int l,int r,int d){
        t[nod].l=l,t[nod].r=r,t[nod].len=r-l+1;
        t[nod].s[0]=t[nod].s[1]=0;
        t[nod].tag=-1;
        if(l==r){
    	    t[nod].s[a[l]>=d]=1;
    	    return ;
    	}
    	build(lson,d); build(rson,d);
    	pushup(nod);
    }
    
    void update(int nod,int l,int r,int ll,int rr,int v){
        if(ll>rr) return ;
    	if(l==ll&&r==rr){
    	    t[nod].s[v]=t[nod].len; t[nod].s[1-v]=0;
    	    t[nod].tag=v;
    	    return ;
    	}
    	pushdown(nod);
    	if(rr<=mid) update(lson,ll,rr,v);
    	else if(ll>mid) update(rson,ll,rr,v);
    	else update(lson,ll,mid,v),update(rson,mid+1,rr,v);
    	pushup(nod);
    }
    
    int query(int nod,int l,int r,int ll,int rr){
        if(ll>rr) return 0;
    	if(l==ll&&r==rr) return t[nod].s[1];
        pushdown(nod);
        if(rr<=mid) return query(lson,ll,rr);
        else if(ll>mid) return query(rson,ll,rr);
        else return query(lson,ll,mid)+query(rson,mid+1,rr);
    }
    
    int check(int d){
        build(1,1,n,d);
        //cout<<"ok1"<<endl;
        for(int i=1;i<=m;i++){
    	    int x=query(1,1,n,b[i].l,b[i].r);
    	    //cout<<"ok2"<<endl;
    	    if(b[i].opt){
    		    update(1,1,n,b[i].l,b[i].l+x-1,1);
    		    update(1,1,n,b[i].l+x,b[i].r,0);
    		}else{
    		    update(1,1,n,b[i].l,b[i].r-x,0);
    		    update(1,1,n,b[i].r-x+1,b[i].r,1);
    		}
    		//cout<<"ok3"<<endl;
    	}
    	return query(1,1,n,pos,pos);
    }
    
    signed main() {
        n=read(),m=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=m;i++){
    	    b[i].opt=read(),b[i].l=read(),b[i].r=read();
    	}
    	pos=read();
    	
    	int l=1,r=n,ans=-1;
    	while(l<=r){
    		int Mid=(l+r)>>1;
    	    if(check(Mid)) { ans=Mid; l=Mid+1; }
    	    else r=Mid-1;
    	}
    	
    	printf("%d",ans);
    	return 0;
    }
    
    
    
  • 相关阅读:
    react 添加addEventListener事件
    C#中 Queue List LinkedList 性能对比
    Nginx中proxy_pass的斜杠(/)问题
    原码,补码和反码
    Base64原理
    springsessiondataredis session同步的使用
    中间件redis常用命令
    java项目中的classpath的理解
    linux环境oracle设置环境变量
    Redis 主从复制的原理及演进
  • 原文地址:https://www.cnblogs.com/zzhzzh123/p/12061502.html
Copyright © 2020-2023  润新知