【BZOJ4552】[Tjoi2016&Heoi2016]排序 二分+线段树

【BZOJ4552】[Tjoi2016&Heoi2016]排序

Description

在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q位置上的数字。

Input

输入数据的第一行为两个整数n和m。n表示序列的长度,m表示局部排序的次数。1 <= n, m <= 10^5第二行为n个整数,表示1到n的一个全排列。接下来输入m行,每一行有三个整数op, l, r, op为0代表升序排序,op为1代表降序排序, l, r 表示排序的区间。最后输入一个整数q,q表示排序完之后询问的位置, 1 <= q <= n。1 <= n <= 10^5,1 <= m <= 10^5

Output

 输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。

Sample Input

6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3

Sample Output

5

题解:思路非常巧妙,先二分答案,然后将>=mid的位置看成1,其余看成0,然后排序就变成了将段区间的1全都放到左边或右边,这个用线段树很容易搞定。

单调性也十分显然,如果原来的结果是1,那么在增加一个1后,结果不可能变为0;如果原来的结果是0,那么在去掉一个1后,结果不可能变为1。

 

#include <cstdio>
#include <cstring>
#include <iostream>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=100010;
int n,m,now,pos;

int s[maxn<<2],tag[maxn<<2],pa[maxn],pb[maxn],op[maxn],v[maxn];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
inline void pushdown(int l,int r,int x)
{
	if(tag[x]!=-1)
	{
		int mid=(l+r)>>1;
		s[lson]=(mid-l+1)*tag[x],s[rson]=(r-mid)*tag[x],tag[lson]=tag[rson]=tag[x];
		tag[x]=-1;
	}
}
void build(int l,int r,int x)
{
	tag[x]=-1;
	if(l==r)
	{
		s[x]=(v[l]>=now);
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,lson),build(mid+1,r,rson);
	s[x]=s[lson]+s[rson];
}
void updata(int l,int r,int x,int a,int b,int c)
{
	if(a>b)	return ;
	if(a<=l&&r<=b)
	{
		s[x]=(r-l+1)*c,tag[x]=c;
		return ;
	}
	pushdown(l,r,x);
	int mid=(l+r)>>1;
	if(a<=mid)	updata(l,mid,lson,a,b,c);
	if(b>mid)	updata(mid+1,r,rson,a,b,c);
	s[x]=s[lson]+s[rson];
}
int query(int l,int r,int x,int a,int b)
{
	if(a<=l&&r<=b)	return s[x];
	pushdown(l,r,x);
	int mid=(l+r)>>1;
	if(b<=mid)	return query(l,mid,lson,a,b);
	if(a>mid)	return query(mid+1,r,rson,a,b);
	return query(l,mid,lson,a,b)+query(mid+1,r,rson,a,b);
}
bool check()
{
	build(1,n,1);
	int i,a;
	for(i=1;i<=m;i++)
	{
		a=query(1,n,1,pa[i],pb[i]);
		if(op[i])	updata(1,n,1,pa[i],pa[i]+a-1,1),updata(1,n,1,pa[i]+a,pb[i],0);
		else	updata(1,n,1,pa[i],pb[i]-a,0),updata(1,n,1,pb[i]-a+1,pb[i],1);
	}
	return query(1,n,1,pos,pos);
}
int main()
{
	n=rd(),m=rd();
	int i,l=1,r=n+1;
	for(i=1;i<=n;i++)	v[i]=rd();
	for(i=1;i<=m;i++)	op[i]=rd(),pa[i]=rd(),pb[i]=rd();
	pos=rd();
	while(l<r)
	{
		now=(l+r)>>1;
		if(check())	l=now+1;
		else	r=now;
	}
	printf("%d",l-1);
	return 0;
}

 

posted @ 2017-10-15 15:09  CQzhangyu  阅读(270)  评论(0编辑  收藏  举报