題目大意
一個長度為 n 的序列 a ,設其排過序之後為 b ,其中位元定義為 b[n/2] ,其中 a,b 從 0 開始標號 , 除法取下整。
給你一個長度為 n 的序列 s 。回答 Q 個這樣的詢問 : s 的左端點在 [a,b] 之間 , 右端點在 [c,d] 之間的子序列中 ,最大的中位元。
其中 a<b<c<d a。
位置也從 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;}