与中位数有关的题二分答案是很常用的trick。二分答案之后,将所有大于它的看成1小于它的看成-1,那么只需要判断是否存在满足要求的一段和不小于0。
由于每个位置是1还是-1并不固定,似乎不是很好算。考虑暴力一点的想法:对于每一种答案预处理。这样查询就很好办了,线段树上每个区间维护最大前缀和后缀和及总和即可。并且可以发现按答案从小到大考虑的话每个位置都是开始一段为1之后为-1,总修改次数只有n次,建主席树即可。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 20010
int n,m,a[N],b[N],root[N],lastans,cnt=;
vector<int> p[N];
struct data{int l,r,sum,pre,suf;
}tree[N<<];
void build(int &k,int l,int r)
{
k=++cnt;tree[k].sum=tree[k].pre=tree[k].suf=r-l+;
if (l==r) return;
int mid=l+r>>;
build(tree[k].l,l,mid);
build(tree[k].r,mid+,r);
}
void modify(int &k,int l,int r,int x)
{
tree[++cnt]=tree[k];k=cnt;
tree[k].sum-=;
if (l==r) {tree[k].pre=tree[k].suf=-;return;}
int mid=l+r>>;
if (x<=mid) modify(tree[k].l,l,mid,x);
else modify(tree[k].r,mid+,r,x);
tree[k].pre=max(tree[tree[k].l].pre,tree[tree[k].l].sum+tree[tree[k].r].pre);
tree[k].suf=max(tree[tree[k].r].suf,tree[tree[k].r].sum+tree[tree[k].l].suf);
}
int querysum(int k,int l,int r,int x,int y)
{
if (x>y) return ;
if (l==x&&r==y) return tree[k].sum;
int mid=l+r>>;
if (y<=mid) return querysum(tree[k].l,l,mid,x,y);
else if (x>mid) return querysum(tree[k].r,mid+,r,x,y);
else return querysum(tree[k].l,l,mid,x,mid)+querysum(tree[k].r,mid+,r,mid+,y);
}
int querypre(int k,int l,int r,int x,int y)
{
if (l==x&&r==y) return tree[k].pre;
int mid=l+r>>;
if (y<=mid) return querypre(tree[k].l,l,mid,x,y);
else if (x>mid) return querypre(tree[k].r,mid+,r,x,y);
else return max(querypre(tree[k].l,l,mid,x,mid),querysum(tree[k].l,l,mid,x,mid)+querypre(tree[k].r,mid+,r,mid+,y));
}
int querysuf(int k,int l,int r,int x,int y)
{
if (l==x&&r==y) return tree[k].suf;
int mid=l+r>>;
if (y<=mid) return querysuf(tree[k].l,l,mid,x,y);
else if (x>mid) return querysuf(tree[k].r,mid+,r,x,y);
else return max(querysuf(tree[k].r,mid+,r,mid+,y),querysum(tree[k].r,mid+,r,mid+,y)+querysuf(tree[k].l,l,mid,x,mid));
}
int calc(int k,int a,int b,int c,int d)
{
return querysum(root[k],,n,b+,c-)+querysuf(root[k],,n,a,b)+querypre(root[k],,n,c,d);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj2653.in","r",stdin);
freopen("bzoj2653.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read();
for (int i=;i<=n;i++) b[i]=a[i]=read();
sort(b+,b+n+);
int t=unique(b+,b+n+)-b;
for (int i=;i<=n;i++)
{
a[i]=lower_bound(b+,b+t,a[i])-b;
p[a[i]].push_back(i);
}
build(root[],,n);
for (int i=;i<t;i++)
{
root[i]=root[i-];
for (int j=;j<p[i-].size();j++)
modify(root[i],,n,p[i-][j]);
}
m=read();
while (m--)
{
int q[]={(read()+lastans)%n,(read()+lastans)%n,(read()+lastans)%n,(read()+lastans)%n};
sort(q,q+);
int l=,r=t-,ans=;
while (l<=r)
{
int mid=l+r>>;
if (calc(mid,q[]+,q[]+,q[]+,q[]+)>=) ans=mid,l=mid+;
else r=mid-;
}
printf("%d\n",lastans=b[ans]);
}
return ;
}