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


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
#include
#include
#include
#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&&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&&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<=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 "<>1;
		//cout<<"L "<