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;
}