2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串)

https://www.luogu.com.cn/problem/P2824

题意:

在 2016 年,佳媛姐姐喜欢上了数字序列。因而她经常研究关于序列的一些奇奇怪怪的问题,现在她在研究一个难题,需要你来帮助她。

这个难题是这样子的:给出一个 1 到 n 的排列,现在对这个排列序列进行 m 次局部排序,排序分为两种:

  • 0 l r 表示将区间 \([l,r]\) 的数字升序排序
  • 1 l r 表示将区间 \([l,r]\) 的数字降序排序

注意,这里是对下标在区间 \([l,r]\) 内的数排序。
最后询问第 \(q\) 位置上的数字。

分析:

先二分答案二分出位置 \(p\) 上可能的结果 \(maxn\) ,把大于等于 \(maxn\) 的数全部标成 \(1\) ,否则标成 \(0\) 。这样对于一个 \(01\) 串进行升序或降序排序就是把一个区间分成两半,一半全部区间修改 \(1\) ,另一半修改成 \(0\) 。对于位置 \(p\) ,如果这个节点上是 \(1\) ,那么就能肯定这个数大于等于 \(maxn\) ,不断二分,直至确定这个数究竟是多少。

代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ls (x<<1)
#define rs (x<<1)|1
using namespace std;

const int N=1e5+10;
int n,m,val[N],p,a[N];
struct node{
	int len,sum,lazy;
}t[N<<3];
struct nodei{
	int op,l,r;
}q[N];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void update(int x){
	t[x].sum=t[ls].sum+t[rs].sum;
}
inline void pre_pushdown(int x,int flag){
	if(flag==1)t[x].sum=t[x].len;
	else t[x].sum=0;
}
inline void pushdown(int x){
	if(t[x].lazy==-1)return ;
	t[ls].lazy=t[rs].lazy=t[x].lazy;
	pre_pushdown(ls,t[x].lazy);
	pre_pushdown(rs,t[x].lazy);
	t[x].lazy=-1;
}
inline void build(int x,int l,int r,int maxn){
	t[x].lazy=-1;t[x].len=r-l+1;
	if(l==r)return (void)(t[x].sum=val[l]>=maxn);
	int mid=(l+r)>>1;
	build(ls,l,mid,maxn);
	build(rs,mid+1,r,maxn);
	update(x);
}
inline int query(int x,int l,int r,int L,int R){
	if(l>R||r<L)return 0;
	if(l>=L&&r<=R)return t[x].sum;
	pushdown(x);
	int mid=(l+r)>>1;
	int ans=0;
	if(L<=mid)ans+=query(ls,l,mid,L,R);
	if(R>mid)ans+=query(rs,mid+1,r,L,R);
	update(x);
	return ans;
}
inline void change(int x,int l,int r,int L,int R,int k){
	if(l>R||r<L)return ;
	if(l>=L&&r<=R){
		t[x].lazy=k;
		pre_pushdown(x,k);
		return ;
	}
	pushdown(x);
	int mid=(l+r)>>1;
	if(L<=mid)change(ls,l,mid,L,R,k);
	if(R>mid)change(rs,mid+1,r,L,R,k);
	update(x);
}
inline void find(){
	for(int i=1;i<=n;i++)cout<<query(1,1,n,i,i)<<" ";cout<<endl;
}
inline bool check(int maxn){
	build(1,1,n,maxn);
	//cout<<"maxn "<<maxn<<endl;
	//find();
	for(int i=1;i<=m;i++){
		int len=query(1,1,n,q[i].l,q[i].r);
		if(q[i].op==0){
			change(1,1,n,q[i].r-len+1,q[i].r,1);
			if(q[i].r-len>=q[i].l)change(1,1,n,q[i].l,q[i].r-len,0);
		}else{
			change(1,1,n,q[i].l,q[i].l+len-1,1);
			if(q[i].l+len<=q[i].r)change(1,1,n,q[i].l+len,q[i].r,0);
		}
		//cout<<"op "<<q[i].op<<" l "<<q[i].l<<" r "<<q[i].r<<" len "<<len<<endl;
		//find();
	}
	if(query(1,1,n,p,p))return true;
	else return false;
}
inline void erfen(){
	int L=1,R=n,mid,ans=0;
	//sort(a+1,a+n+1);
	while(L<=R){
		mid=(L+R)>>1;
		//cout<<"L "<<L<<" R "<<R<<" mid "<<mid<<endl;
		if(check(mid))L=mid+1,ans=mid;
		else R=mid-1;
	}
	cout<<ans;
}

int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++)val[i]=a[i]=read();
	for(int i=1;i<=m;i++)q[i].op=read(),q[i].l=read(),q[i].r=read();
	p=read();
	erfen();
	return 0;
}
 posted on 2021-12-09 15:44  eleveni  阅读(43)  评论(0)    收藏  举报