首先做这个题 我们要用到一个常用的技巧 二分求中位数
具体步骤就是 先二分一个值 在数组中把大于等于这个值的数都设为1 把小于这个值的数都设为-1
如果数组和>=0 那么 l=mid+1
否则的话 r=mid-1
那么我们如何快速的进行这个操作呢
假如一个询问是 a,b,c,d a<b<c<d 并且对于 区间a~d我们都进行了上述的赋值操作
那么 b+1~c-1之间的值是肯定要算进去的
然后我们需要在 a~b区间内找个最大后缀和 在 c~d区间内找个最大前缀和 就可以完成了
可是如何快速进行这样的+1和-1赋值
首先我们知道中位数肯定是数组中的某个数 容易想到的是 我们把数组的数按照升序排序 在二分下标 最后得到中位数 而这个下标其实可以对应一棵 1~i 的前缀主席树了
主席树维护 和,最大前缀和,最大后缀和 当i=1的时候 区间所有的数都是大于等于它的 所以初始化为 r-l+1 (也就是每个位置都对应1) 当i=2时 因为i=1对应的值小于它 所以我们把它对应的位置-置为-1 后面的树也进行类似的操作
那么当我们二分到一个mid值时 我们就到对应的树上面去查
首先 加上 b+1~c-1的和 其次 加上 a~b的最大后缀 最后加上 c~d的最大前缀 如果总和>=0 则 l=mid+1 否则 r=mid-1
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int rt[N],id[N],val[N],tot,q[4],n;
inline int in(){
int w=0,x=0;char c=0;
while(c<'0'||c>'9') w|=c=='-',c=getchar();
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return w?-x:x;
}
struct Mx{
int lmax,rmax,sum;
void init(){
lmax=rmax=-N,sum=0;
}
}ans;
struct hjt{
int ls,rs;
Mx v;
}T[N*30];
bool cmp(int a,int b){
return val[a]<val[b];
}
Mx merge(Mx A,Mx B){
Mx C;
C.lmax = max(A.lmax, A.sum + B.lmax);
C.rmax = max(B.rmax, A.rmax + B.sum);
C.sum = A.sum + B.sum;
return C;
}
void build(int &o,int l,int r){
o=++tot;
T[o].v.lmax=T[o].v.rmax=T[o].v.sum=r-l+1;
if(l==r) return;
int mid = l+r>>1;
build(T[o].ls,l,mid);
build(T[o].rs,mid+1,r);
}
void upd(int &o,int l,int r,int pos,int v){
T[++tot]=T[o];
o=tot;
if(l==r){
T[o].v.lmax=T[o].v.rmax=T[o].v.sum=v;
return;
}
int mid = l+r>>1;
if(pos<=mid) upd(T[o].ls,l,mid,pos,v);
else upd(T[o].rs,mid+1,r,pos,v);
T[o].v = merge(T[T[o].ls].v, T[T[o].rs].v);
}
void query(int o,int l,int r,int L,int R){
if(L<=l&&R>=r){
ans=merge(ans,T[o].v);
return;
}
int mid = l+r>>1;
if(L<=mid) query(T[o].ls,l,mid,L,R);
if(R>mid) query(T[o].rs,mid+1,r,L,R);
}
bool check(int mid){
//printf("mid=%d\n",mid);
int val=0;
if(q[1]+1<=q[2]-1) ans.init(),query(rt[mid],1,n,q[1]+1,q[2]-1),val+=ans.sum;
ans.init();query(rt[mid],1,n,q[0],q[1]),val+=ans.rmax;
ans.init();query(rt[mid],1,n,q[2],q[3]);val+=ans.lmax;
return val>=0;
}
int main(){
n=in();
build(rt[1],1,n);
T[0].v.init();
for(int i = 1; i <= n; i++)
val[i]=in(),id[i]=i;
sort(id+1,id+1+n,cmp);
for(int i = 2; i <= n; i++){
rt[i]=rt[i-1];
//printf("i=%d\n",i);
upd(rt[i],1,n,id[i-1],-1);
}
int m,las=0;
m=in();
for(int i = 1; i <= m; i++){
for(int i = 0; i < 4; i++)
q[i]=(in()+las)%n+1;
sort(q,q+4);
int l=1,r=n;
while(l<=r){
int mid = l+r>>1;
if(check(mid)) las=val[id[mid]],l=mid+1;
else r=mid-1;
}
printf("%d\n",las);
}
return 0;
}