「HEOI2016/TJOI2016」 排序

题目链接

戳我

\(Solution\)

这道题在线的做法不会,所以这里就只讲离线的做法。

因为直接排序的话复杂度显然不对.但是如果数列为\(01\)串的话就可以让复杂度变成对的了

那么\(01\)串怎么做呢?

我们考虑用线段树维护这个东西.

假设我们要将\([l,r]\)排序

我们可以处理出\([l,r]\)\(1\)的个数,我们令他为\(w\)

如果升序就将\([r-x+1,r]\)设为1,其余为\(0\)

如果降序就将\([l,l+x-1]\)设为1,其余为\(0\)

那么这个问题怎么变成上述情况呢?

我们二分最后的答案,令这个数为\(mid\)

对于序列中的数,如果小于\(mid\)就为\(0\),大于\(mid\)就为\(1\)

然后操作根上述过程一样.

最后判断下\(q\)位置是否为\(1\)

是,\(l=mid+1\)

否,\(r=mid-1\)

现在来证明一下这个单调性。

如果\(q\)这个位置的数为\(1\),那么答案肯定为\(x+1,x+2,x+3...\)所以区间右移,反之亦然。

\(Code\)

#include<bits/stdc++.h>
#define rg register
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
    return f*x;
}
struct node {
	int lazy,v;
}a[1000001];
int c[1000001];
void pushup(int k){
	a[k].v=a[k<<1].v+a[k<<1|1].v;
}
void build(int k,int l,int r){
	a[k].lazy=-1,a[k].v=0;
	if(l==r)
		return;
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
}
void pushdown(int k,int l,int r){
	if(a[k].lazy==-1) return;
	int mid=(l+r)>>1;
	a[k<<1].v=(mid-l+1)*a[k].lazy;
	a[k<<1|1].v=(r-mid)*a[k].lazy;
	a[k<<1].lazy=a[k<<1|1].lazy=a[k].lazy;
	a[k].lazy=-1;
}
void update(int k,int l,int r,int begin,int end,int v){
	if(r<begin||l>end) return ;
	if(r<=end&&l>=begin){
		a[k].v=(r-l+1)*v;
		a[k].lazy=v;
		return ;
	}
	pushdown(k,l,r);
	int mid=(l+r)>>1;
	update(k<<1,l,mid,begin,end,v);
	update(k<<1|1,mid+1,r,begin,end,v);
	pushup(k);
}
int find(int k,int l,int r,int begin,int end){
	if(r<begin&&l>end) return 0;
	if(r<=end&&l>=begin) return a[k].v;
	pushdown(k,l,r);
	int mid=(l+r)>>1;
	if(end<=mid)
		return find(k<<1,l,mid,begin,end);
	else if(begin>mid)
		return find(k<<1|1,mid+1,r,begin,end);
	else return find(k<<1,l,mid,begin,mid)+find(k<<1|1,mid+1,r,mid+1,end);
}
struct ans{
	int opt,x,y;
}b[1000001];
int n,m,ans,l,r,q;
bool check(int x){
	build(1,1,n);
	for(int i=1;i<=n;i++)
		update(1,1,n,i,i,c[i]>=x);
	for(int i=1;i<=m;i++){
		int opt=b[i].opt,x=b[i].x,y=b[i].y;
		int w1=find(1,1,n,x,y),w0=y-x+1-w1;
		if(opt==0)
			update(1,1,n,x,y,1),update(1,1,n,x,x+w0-1,0);
		else update(1,1,n,x,y,0),update(1,1,n,x,x+w1-1,1);
	}
	return find(1,1,n,q,q)==1;
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++) c[i]=read();
	for(int i=1;i<=m;i++) b[i].opt=read(),b[i].x=read(),b[i].y=read();
	l=1,r=n,q=read();
	while(l<=r){
		int mid=(l+r)>>1;
		if(check(mid)) l=mid+1,ans=mid;
		else r=mid-1;
	}
	printf("%d",ans);
    return 0;
}
posted @ 2019-10-20 20:01  撤云  阅读(217)  评论(1编辑  收藏  举报
……