bzoj 2653: middle

Description

一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。给你一个
长度为n的序列s。回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a<b<c<d。位置也从0开始标号。我会使用一些方式强制你在线。

Solution

中位数的题一般是二分答案
二分一个中位数\(x\),如果是中位数则比它小的数和比它大的数绝对值不超过1
所以把大于\(x\)的数赋成1,小于\(x\)的数赋成-1,如果存在一个区间\([l,r]\)使得区间和等于0就可以满足条件
二分答案之后,要使得区间和尽量大
所以维护一个\([a,b]\)的最大后缀和,\([c,d]\)的最大前缀和,再加上\([b+1,c-1]\)的和就是最大区间的和
所以我们只需要对每一个权值维护一个线段树就行了, 维护方法和区间子段和类似

#include <bits/stdc++.h>
using namespace std;
const int N=20005;
int n,a[N],rt[N],b[N],num,Q,ans=0,q[5],cnt=0,id[N];
struct node{
	int ls,rs;
	int lsum,rsum,sum;
}tr[N*30];
inline void upd(int x){
	int ls=tr[x].ls,rs=tr[x].rs;
	tr[x].sum=tr[ls].sum+tr[rs].sum;
	tr[x].lsum=max(tr[ls].lsum,tr[ls].sum+tr[rs].lsum);
	tr[x].rsum=max(tr[rs].rsum,tr[rs].sum+tr[ls].rsum);
}
inline void build(int &x,int l,int r){
	x=++cnt;
	if(l==r){tr[x].lsum=tr[x].rsum=tr[x].sum=-1;return ;}
	int mid=(l+r)>>1;
	build(tr[x].ls,l,mid);build(tr[x].rs,mid+1,r);
	upd(x);
}
inline void ins(int &x,int l,int r,int sa){
	tr[++cnt]=tr[x];x=cnt;
	if(l==r){tr[x].lsum=tr[x].rsum=tr[x].sum=1;return ;}
	int mid=(l+r)>>1;
	if(sa<=mid)ins(tr[x].ls,l,mid,sa);
	else ins(tr[x].rs,mid+1,r,sa);
	upd(x);
}
inline node qry(int x,int l,int r,int sa,int se){
	if(sa<=l && r<=se)return tr[x];
	int mid=(l+r)>>1;
	if(se<=mid)return qry(tr[x].ls,l,mid,sa,se);
	else if(sa>mid)return qry(tr[x].rs,mid+1,r,sa,se);
	else{
		node ls=qry(tr[x].ls,l,mid,sa,mid);
		node rs=qry(tr[x].rs,mid+1,r,mid+1,se),ret;
		ret.sum=ls.sum+rs.sum;
		ret.lsum=max(ls.lsum,ls.sum+rs.lsum);
		ret.rsum=max(rs.rsum,rs.sum+ls.rsum);
		return ret;
	}
}
inline bool check(int x){
	node A,B,C;int sum=0;
	if(q[1]+1<=q[2]-1)B=qry(rt[x],1,n,q[1]+1,q[2]-1),sum+=B.sum;
	A=qry(rt[x],1,n,q[0],q[1]);sum+=A.rsum;
	C=qry(rt[x],1,n,q[2],q[3]);sum+=C.lsum;
	return sum>=0;
}
int main()
{
	freopen("pp.in","r",stdin);
	freopen("pp.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];
	sort(b+1,b+n+1);
	num=unique(b+1,b+n+1)-b-1;
	for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+num+1,a[i])-b,id[a[i]]=i;
	build(rt[n+1],1,n);
	for(int i=n;i>=1;i--){
		rt[i]=rt[i+1];
		ins(rt[i],1,n,id[i]);
	}
	scanf("%d",&Q);
	while(Q--){
		for(int i=0;i<4;i++)scanf("%d",&q[i]),q[i]=(q[i]+ans)%n+1;
		sort(q,q+4);
		int l=1,r=num,mid,ret=0;
		while(l<=r){
			mid=(l+r)>>1;
			if(check(mid))ret=mid,l=mid+1;
			else r=mid-1;
		}
		printf("%d\n",ans=b[ret]);
	}
	return 0;
}

posted @ 2018-02-06 11:39  PIPIBoss  阅读(120)  评论(0编辑  收藏  举报