题目大意
一个长度为 n 的序列 a ,设其排过序之后为 b ,其中位数定义为 b[n/2] ,其中 a,b 从 0 开始标号 , 除法取下整。
给你一个长度为 n 的序列 s 。回答 Q 个这样的询问 : s 的左端点在 [a,b] 之间 , 右端点在 [c,d] 之间的子序列中 ,最大的中位数。
其中
a<b<c<d
。
位置也从 0 开始标号。
我会使用一些方式强制你在线。
解题思路
考虑求一个区间里的中位数,我们会二分答案,检查大于等于答案减小于答案的个数,如果大于等于0答案就有可能更大,越大答案就越大。那我们发现[b+1,c-1]一定要取,[a,b]取右数最大值,[c,d]取左数最大值,加起来就可以调整答案。
假设当前答案为x,那我们把大于等于x的位置都标为1,小于的位置标为-1就可以用线段树维护以上信息。我们发现不同的答案只有n个,我们对每一个x都维护一颗线段树即可,发现相邻两个x不同权值的位置有一个,那我们可以按x的大小顺序建线段树,利用之前的信息就可以快速求出当前线段树,用可持久化线段树即可。
code
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LF double
#define LL long long
#define Min(a,b) ((a<b)?a:b)
#define Max(a,b) ((a>b)?a:b)
#define Fo(i,j,k) for(int i=j;i<=k;i++)
#define Fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const Mxn=2*1e4,Mxnm=1e5;
int N,Pon,A[Mxn+9],B[Mxn+9],C[9],T[Mxn*20+9][3],Son[Mxn*20+9][2];
bool Cmp(int X,int Y){return A[X]<A[Y];}
void Update(int Now){
T[Now][0]=T[Son[Now][0]][0]+T[Son[Now][1]][0];
T[Now][1]=Max(T[Son[Now][0]][1],T[Son[Now][0]][0]+T[Son[Now][1]][1]);
T[Now][2]=Max(T[Son[Now][1]][2],T[Son[Now][0]][2]+T[Son[Now][1]][0]);
}
void Build(int Now,int L,int R){
if(L==R){
T[Now][0]=T[Now][1]=T[Now][2]=1;
return;
}
int Mid=(L+R)>>1;
Son[Now][0]=++Pon;Son[Now][1]=++Pon;
Build(Son[Now][0],L,Mid);Build(Son[Now][1],Mid+1,R);
Update(Now);
}
void Oper(int Pre,int Now,int L,int R,int V){
if(L==R){
T[Now][0]=T[Now][1]=T[Now][2]=-1;
return;
}
int Mid=(L+R)>>1;
if(V<=Mid){
Son[Now][1]=Son[Pre][1];
Son[Now][0]=++Pon;
Oper(Son[Pre][0],Son[Now][0],L,Mid,V);
}else{
Son[Now][0]=Son[Pre][0];
Son[Now][1]=++Pon;
Oper(Son[Pre][1],Son[Now][1],Mid+1,R,V);
}
Update(Now);
}
int Qury(int Now,int L,int R,int L1,int R1,int Op){
int Mid=(L+R)>>1;
if((L==L1)&&(R==R1))return T[Now][Op];
else if(R1<=Mid)return Qury(Son[Now][0],L,Mid,L1,R1,Op);
else if(Mid<L1)return Qury(Son[Now][1],Mid+1,R,L1,R1,Op);
else if(!Op)return Qury(Son[Now][0],L,Mid,L1,Mid,Op)
+Qury(Son[Now][1],Mid+1,R,Mid+1,R1,Op);
else if(Op==1){
int X1=Qury(Son[Now][0],L,Mid,L1,Mid,Op),
X2=Qury(Son[Now][0],L,Mid,L1,Mid,0)
+Qury(Son[Now][1],Mid+1,R,Mid+1,R1,Op);
return Max(X1,X2);
}else{
int X1=Qury(Son[Now][0],L,Mid,L1,Mid,Op)+
Qury(Son[Now][1],Mid+1,R,Mid+1,R1,0),
X2=Qury(Son[Now][1],Mid+1,R,Mid+1,R1,Op);
return Max(X1,X2);
}
}
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d",&N);Pon=N;
Fo(i,1,N)scanf("%d",&A[i]),B[i]=i;
sort(B+1,B+N+1,Cmp);
Build(1,1,N);
Fo(i,2,N)Oper(i-1,i,1,N,B[i-1]);
int Q,Last=0;scanf("%d",&Q);
Fo(cas,1,Q){
Fo(i,1,4)scanf("%d",&C[i]),C[i]=(C[i]+Last)%N+1;
sort(C+1,C+5);
int L=1,R=N,Mid;
while(L!=R){
Mid=(L+R+1)>>1;
if(Qury(Mid,1,N,C[1],C[2],2)+Qury(Mid,1,N,C[3],C[4],1)
+((C[2]+1!=C[3])?Qury(Mid,1,N,C[2]+1,C[3]-1,0):0)>=0)L=Mid;
else R=Mid-1;
}
printf("%d\n",Last=A[B[L]]);
}
return 0;
}