洛谷 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;
}


原文地址:https://www.cnblogs.com/zzhzzh123/p/12061502.html