[HEOI2016/TJOI2016]排序

[HEOI2016/TJOI2016]排序

洛谷题目链接

这道题不难,但是挺有意思的。


题解

先讲一些思路:

\(l=1,r=n\)​​​​​二分答案,将所有大于\(mid\)​​​​​的序列修改为\(1\)​​​​​,其余就修改为\(0\)​​​​​,然后对其进行局部排序,升序排序将局部中所有的\(1\)​​​​​排在后边,降序排序将局部中所有的\(1\)​​​​​排在前面,最后查询\(q\)​​​​位上是否为\(1\)​​​​,如果\(a_q==1\)​​​​,则\(ans=mid,l=mid+1\)​​​​,否则,\(r=mid-1\)​​​​。


解释

我们想,因为是全排列,所有\(a_i=1...n\)​​,当我们二分时,如果经过了序列操作最后\(a_q==1\)​,那么说明我们按照当前的\(ans=mid\)​得出的结果是大于等于真正的\(ans\)​,因为开始时我们将所有大于等于\(mid\)​的位置上都赋值为了\(1\)​,只有当答案在\(a_{mid...r}\)​时经过操作\(q\)​位置上才为\(1\)​。\(a_q==0\)​的情况与之相反,因为需要区间修改所以用线段树或者树状数组维护。


代码

#include<bits/stdc++.h>
using namespace std;
const int MN=1e5+100;
int n,m,q,ans,num[MN];
struct node{
	int op,l,r;
}a[MN];
void input(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)scanf("%d",&num[i]);
	for(int i=1,op,l,r;i<=m;++i)scanf("%d%d%d",&a[i].op,&a[i].l,&a[i].r);
	scanf("%d",&q);
}
#define lc id<<1
#define rc id<<1|1
struct tree{
	int l,r,sum;
}t[MN<<2];
int tag[MN<<2];
void pushdown(int id){
	if(tag[id]==-1)return;
	t[lc].sum=(t[lc].r-t[lc].l+1)*tag[id],tag[lc]=tag[id];
	t[rc].sum=(t[rc].r-t[rc].l+1)*tag[id],tag[rc]=tag[id];
	tag[id]=-1;
}
void pushup(int id){
	t[id].sum=t[lc].sum+t[rc].sum;
}
void build(int id,int l,int r){
	t[id].l=l,t[id].r=r,tag[id]=-1;\\因为tag我们赋值为了0,1所以初始化为-1
	if(l==r)return;
	int mid=(l+r)>>1;
	build(lc,l,mid),build(rc,mid+1,r);
}
void update(int id,int l,int r,int k){
	if(t[id].l>=l&&t[id].r<=r){
		tag[id]=k;
		t[id].sum=(t[id].r-t[id].l+1)*k;
		return;
	}
	int mid=(t[id].r+t[id].l)>>1;
	if(tag[id]!=-1)pushdown(id);
	if(l<=mid)update(lc,l,r,k);
	if(r>=mid+1)update(rc,l,r,k);
	pushup(id);
}
int get_sum(int id,int l,int r){
	if(t[id].l>=l&&t[id].r<=r){
		return t[id].sum;
	}
	int mid=(t[id].r+t[id].l)>>1,ans=0;
	pushdown(id);
	if(l<=mid)ans+=get_sum(lc,l,r);
	if(r>=mid+1)ans+=get_sum(rc,l,r);
	return ans;
}
bool pd(int x){
	update(1,x,n,1);
	update(1,1,x-1,0);
	for(int i=1;i<=m;++i){
		if(a[i].op){
			int cnt=get_sum(1,a[i].l,a[i].r);
			if(cnt==0||(a[i].r-a[i].l+1)==cnt)continue;\\全是0,1时不需要修改
			update(1,a[i].l,a[i].l+cnt-1,1);
			update(1,a[i].l+cnt,a[i].r,0);
			
		}
		else{
			int cnt=get_sum(1,a[i].l,a[i].r);
			if(cnt==0||(a[i].r-a[i].l+1)==cnt)continue;
			update(1,a[i].l,a[i].r-cnt,0);
			update(1,a[i].r-cnt+1,a[i].r,1);
		}
	}
	return get_sum(1,q,q);
}
void lower(int q){
	int l=1,r=n,mid;
	while(l<=r){
		mid=(l+r)>>1;
		pd(mid)==1?ans=mid,l=mid+1:r=mid-1;
	}
}
int main(){
	freopen("sort.in","r",stdin);
	freopen("sort.out","w",stdout);
	input();
	build(1,1,n);
	lower(q);
	printf("%d\n",ans);
	return 0;
}
posted @ 2021-08-11 17:23  fanner_rick  阅读(51)  评论(0)    收藏  举报