BZOJ4552 [Tjoi2016&Heoi2016]排序

BZOJ4552 [Tjoi2016&Heoi2016]排序


题目描述

传送门

题目分析

对于一个排列直接找明显不现实,考虑将其转化成一个比较容易计算的排列上去。

明显对于一个\(01\)序列,我们进行如上操作是很容易的,首先计算区间内\(1\)的个数\(cnt\),然后以升序排列为例,我们将\([L,R-cnt]\)的部分区间覆盖为\(0\),将\([R-cnt+1,R]\)的部分区间覆盖为\(1\)就可以了。

发现只有一组询问,考虑二分。

可以二分一个数,然后将比这个数小的置为\(0\),其余的置为\(1\)。然后对这个数列进行\(check\)。如果最后这个位置上是\(1\)就说明答案要更大,否则更小。

是代码呢

#include <bits/stdc++.h>
using namespace std;
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
const int MAXN=2e5+7;
int sum[MAXN],tag[MAXN],b[MAXN],n,m,Q,a[MAXN],ans;
struct po{
	int opt,l,r;
}q[MAXN];
inline void pushup(int rt){sum[rt]=sum[ls]+sum[rs];}
inline void pushdown(int l,int r,int rt)
{
	if(tag[rt]!=-1){
		sum[ls]=(mid-l+1)*tag[rt];
		sum[rs]=(r-mid)*tag[rt];
		tag[ls]=tag[rs]=tag[rt];
		tag[rt]=-1;
	}
}
inline void build(int l,int r,int rt)
{
	tag[rt]=-1;
	if(l==r){
		sum[rt]=b[l];return;
	}
	build(l,mid,ls);build(mid+1,r,rs);
	pushup(rt);
}
inline void update(int L,int R,int k,int l,int r,int rt){
	if(L<=l&&r<=R){
		sum[rt]=(r-l+1)*k;tag[rt]=k;
		return;
	}
	pushdown(l,r,rt);
	if(L<=mid) update(L,R,k,l,mid,ls);
	if(R>mid) update(L,R,k,mid+1,r,rs);
	pushup(rt);
}
inline int query(int L,int R,int l,int r,int rt)
{
	if(l>R||r<L) return 0;
	pushdown(l,r,rt);
	if(L<=l&&r<=R) return sum[rt];
	return query(L,R,l,mid,ls)+query(L,R,mid+1,r,rs);
}
inline int check(int x)
{
	for(int i=1;i<=n;i++) b[i]=(a[i]>=x)?1:0;
	build(1,n,1);
	for(int i=1;i<=m;i++){
		int cnt=query(q[i].l,q[i].r,1,n,1);
//		cout<<q[i].l<<" "<<q[i].r<<endl;
		if(q[i].opt==0){
			if(cnt!=q[i].r-q[i].l+1)update(q[i].l,q[i].r-cnt,0,1,n,1);
			if(cnt>0)update(q[i].r-cnt+1,q[i].r,1,1,n,1);
		} else {
			if(cnt>0)update(q[i].l,q[i].l+cnt-1,1,1,n,1);
			if(cnt!=q[i].r-q[i].l+1)update(q[i].l+cnt,q[i].r,0,1,n,1);
		}
	}
	int d=query(Q,Q,1,n,1);
	return d;
}
inline int read()
{
    int x=0,c=1;
    char ch=' ';
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    while(ch=='-')c*=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*c;
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=m;i++) {int opt=read(),x=read(),y=read();q[i]=(po){opt,x,y};}
	Q=read();
	int l=1,r=n;
	while(l<=r){
		if(check(mid))l=mid+1; 
		else r=mid-1,ans=mid;
	}
	cout<<l-1;
}
对于作者转载文章,欢迎继续转载。 对于作者原创文章,请注明出处之后转载。
posted @ 2019-01-22 10:05  ~victorique~  阅读(76)  评论(0编辑  收藏  举报
Live2D