首页 > 学院 > 开发设计 > 正文

【jzoj2902】【集训队互测 2012】【Middle】【可持久化线段树】

2019-11-06 08:59:33
字体:
来源:转载
供稿:网友

题目大意

一个长度为 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;}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表