題解


[HEOI2016/TJOI2016]排序

題目描述

給出一個 1 到 n 的排列,現在對這個排列序列進行 m 次局部排序,排序分為兩種:

  • 0 l r 表示將區間 \([l,r]\) 的數字升序排序
  • 1 l r 表示將區間 \([l,r]\) 的數字降序排序

注意,這里是對下標在區間 \([l,r]\) 內的數排序。
最后詢問第 q 位置上的數字。
解題思路

注意詢問只有一個,我們可以很難想到用二分答案,假設答案是mid,然后把所有大於等於mid的數

當做1,小於mid的數當做0,這樣我們可以吧排序問題轉化成了區間變成問題,我們就可以用線段樹

來維護了,我們可以統計出線段樹每個區間中1的個數,查詢要排序的區間中1的個數記為cnt,如果

按降序排,前cnt個數變1,剩下的變為0,最后查找要詢問的數,如果是1,二分答案向左半邊找,反

之向右半邊找。

#include<iostream>
#include<cstdio>
#define l(o) (o<<1)
#define r(o) (o<<1|1)
#define mid ((l+r)>>1)
using namespace std;
const int N=2e5+7;
int n,m,p;
int a[N];

struct node{
	int opt,l,r;
}q[N];

int sum[N<<2],tag[N<<2];

void modify(int o,int l,int r,int val){
	tag[o]=val;
	sum[o]=(r-l+1)*val;
}

void up(int o){
	sum[o]=sum[l(o)]+sum[r(o)];
}

void down(int o,int l,int r){
	if(tag[o]!=-1){
		modify(l(o),l,mid,tag[o]);
		modify(r(o),mid+1,r,tag[o]);
		tag[o]=-1;
	}
}

void build(int o,int l,int r,int x){
	tag[o]=-1;
	if(l==r){
		sum[o]=(a[l]>=x);
		return;
	}
	build(l(o),l,mid,x);
	build(r(o),mid+1,r,x);
	up(o);
}

void change(int o,int l,int r,int L,int R,int val){
	if(L<=l&&R>=r){
		modify(o,l,r,val);
		return;
	}
	down(o,l,r);
	if(L<=mid)change(l(o),l,mid,L,R,val);
	if(R>mid)change(r(o),mid+1,r,L,R,val);
	up(o);
}

int ask(int o,int l,int r,int L,int R){
	if(L<=l&&R>=r){
		return sum[o];
	}
	down(o,l,r);
	int res=0;
	if(L<=mid)res+=ask(l(o),l,mid,L,R);
	if(R>mid)res+=ask(r(o),mid+1,r,L,R);
	return res;
}

int judge(int x){
	 build(1,1,n,x);
	 int cnt;
	 for(int i=1;i<=m;i++){
	 	cnt=ask(1,1,n,q[i].l,q[i].r);
	 	if(q[i].opt==1){
	 		if(cnt!=0)change(1,1,n,q[i].l,q[i].l+cnt-1,1);
	 		change(1,1,n,q[i].l+cnt,q[i].r,0);
			  
	 	}else{
	 		change(1,1,n,q[i].l,q[i].r-cnt,0);
	 		if(cnt!=0)change(1,1,n,q[i].r-cnt+1,q[i].r,1);
			 
	 	}
	 }
	 return ask(1,1,n,p,p);
//	 return 0;
}

int main(){
	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",&q[i].opt,&q[i].l,&q[i].r);
	} 
	scanf("%d",&p);
	int l1=1,r1=n;
	int ans;
	while(l1<=r1){
		int mid1=(l1+r1)>>1;
		if(judge(mid1)){
			ans=mid1;
			l1=mid1+1;
		}else r1=mid1-1;
	}
	cout<<ans;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM