[HEOI2016/TJOI2016]排序

题目大意

给出一个 \(1 \sim n\) 的排列,每次操作将 \({[l_i,r_i]}\) 上的数排序(\(opt=0\)升序,\(opt=1\)降序)

最后有一个询问第\(Q\)位上的数

\(n,m \leq 100000\)

解题思路

这题考虑用二分答案和线段树

设当前二分值为\(v\)

将排列中的数\(<v\)的设成\(0\)\(>=v\)的设成\(1\),丢给线段树(\(O(n)\)建树)

每次排序即统计这个区间内\(0\)\(1\)的个数(相当于在线段树中的询问操作),再按照个数覆盖回去

操作完后查询第\(Q\)位上的数

若为\(1\),则答案\(>=v\)

若为\(0\),则答案\(<v\)

举个例子

给定排列1 6 2 5 3 4

当前二分值\(4\)

按上面的方式写成01序列变成0 1 0 1 0 1

此时对\([1,4]\)升序排列变成0 0 1 1 0 1

只要把\(1\)覆盖后面部分,\(0\)覆盖前面部分就完成了排序操作

可以用线段树区间修改维护

注意到,如果最终第\(Q\)位是1,表明这一位至少\(>=4\),这成为了我们继续二分的依据

#include<iostream>
#include<cstdio>
#include<cstring>

const int maxN=200000,Tsize=10000000;
int n,m,S[maxN],opt[maxN],l[maxN],r[maxN],Q;
int T[Tsize],tag[Tsize];

void build(int o,int l,int r,int v){
	if (l==r){
		T[o]=S[l]>=v;
		return;
	}
	int mdl=(l+r)>>1;
	build(o<<1,l,mdl,v);
	build(o<<1|1,mdl+1,r,v);
	T[o]=T[o<<1]+T[o<<1|1];
}

void pushdown(int now,int size){
	if (~tag[now]){
		T[now]=(tag[now])?size:0;
		tag[now<<1]=tag[now<<1|1]=tag[now];
		tag[now]=-1;
	}
}

int query(int o,int l,int r,int L,int R){
	if (l>r) return 0;
	if (l>R||r<L) return 0;
	pushdown(o,r-l+1);
	if (L<=l&&r<=R) return T[o];
	int mdl=(l+r)>>1;
	return query(o<<1,l,mdl,L,R)+query(o<<1|1,mdl+1,r,L,R);
}

int modify(int o,int l,int r,int L,int R,int v){
	if (l>r) return 0;
	pushdown(o,r-l+1);
	if (l>R||r<L) return T[o];
	if (L<=l&&r<=R){tag[o]=v;return (v)?(r-l+1):0;}
	int mdl=(l+r)>>1;
	return T[o]=modify(o<<1,l,mdl,L,R,v)+modify(o<<1|1,mdl+1,r,L,R,v);
}

int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) scanf("%d",&S[i]);
	for (int i=1;i<=m;i++) scanf("%d%d%d",&opt[i],&l[i],&r[i]);
	scanf("%d",&Q);
	int L=1,R=n,mdl;
	while (L<R){
		mdl=(L+R+1)>>1;
		memset(T,0,sizeof(T));
		memset(tag,-1,sizeof(tag));
		build(1,1,n,mdl);
		for (int i=1;i<=m;i++){
			int cnt=query(1,1,n,l[i],r[i]);
			if (opt[i]){
				modify(1,1,n,l[i],l[i]+cnt-1,1);
				modify(1,1,n,l[i]+cnt,r[i],0);
			}
			else{
				modify(1,1,n,l[i],r[i]-cnt,0);
				modify(1,1,n,r[i]-cnt+1,r[i],1);
			}
		}
		int now=query(1,1,n,Q,Q);
		if (now) L=mdl;
		else R=mdl-1;
	}
	printf("%d",L);
}
posted @ 2018-08-04 11:45  ytxytx  阅读(121)  评论(0编辑  收藏  举报