这题思路确实比较难想!建主席树也是非常的特别!
考虑二分答案,如果当前check的答案是 x 那么大于等于 x 的数的贡献是1,其余的贡献是-1,然后就判断一下是否存在总贡献>= 0 的区间,判断的话需要对所有的数建立一个线段树,然后直接建会MLE+TLE,然后就需要我们的黑科技可持久化的数据结构主席树,先把所有的位置都设为1,然后把数排序后从小到大建树每次-1。
非常神的建树方式,从小到大插入数,插入的权值是这个数的位置!!!
正好和我们的正常思路反着…
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
#define ll unsigned long long
#define N 20022
#define mx 1e9
using namespace std;
int sc()
{
int i=0,f=1; char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
return i*f;
}
struct W{int v,pos;}h[N];
int sum[N*500],lmx[N*500],rmx[N*500],ch[N*500][2];
int root[N],q[4];
int n,m,cnt,ans;
bool cmp(W a,W b){return a.v<b.v;}
void push_up(int x)
{
sum[x]=sum[ch[x][0]]+sum[ch[x][1]];
lmx[x]=max(lmx[ch[x][0]],sum[ch[x][0]]+lmx[ch[x][1]]);
rmx[x]=max(rmx[ch[x][1]],sum[ch[x][1]]+rmx[ch[x][0]]);
}
void build(int &x,int l,int r)
{
if(!x)x=++cnt;
if(l==r)
{
sum[x]=lmx[x]=rmx[x]=1;
return;
}
int mid=l+r>>1;
build(ch[x][0],l,mid);
build(ch[x][1],mid+1,r);
push_up(x);
}
void add(int pre,int &x,int l,int r,int v,int f)
{
if(!x)x=++cnt;
if(l==r)
{
lmx[x]=rmx[x]=sum[x]=f;
return;
}
int mid=l+r>>1;
if(v<=mid)
ch[x][1]=ch[pre][1],add(ch[pre][0],ch[x][0],l,mid,v,f);
else
ch[x][0]=ch[pre][0],add(ch[pre][1],ch[x][1],mid+1,r,v,f);
push_up(x);
}
int ask_all(int x,int L,int R,int l,int r)
{
if(L==l&&R==r)return sum[x];
int mid=L+R>>1;
if(r<=mid)return ask_all(ch[x][0],L,mid,l,r);
else if(l>mid)return ask_all(ch[x][1],mid+1,R,l,r);
return ask_all(ch[x][0],L,mid,l,mid)+ask_all(ch[x][1],mid+1,R,mid+1,r);
}
int ask_left(int x,int L,int R,int l,int r)
{
if(L==l&&R==r)return lmx[x];
int mid=L+R>>1;
if(r<=mid)return ask_left(ch[x][0],L,mid,l,r);
else if(l>mid)return ask_left(ch[x][1],mid+1,R,l,r);
return max(ask_left(ch[x][0],L,mid,l,mid),ask_all(ch[x][0],L,mid,l,mid)+ask_left(ch[x][1],mid+1,R,mid+1,r));
}
int ask_right(int x,int L,int R,int l,int r)
{
if(L==l&&R==r)return rmx[x];
int mid=L+R>>1;
if(r<=mid)return ask_right(ch[x][0],L,mid,l,r);
else if(l>mid)return ask_right(ch[x][1],mid+1,R,l,r);
return max(ask_right(ch[x][1],mid+1,R,mid+1,r),ask_all(ch[x][1],mid+1,R,mid+1,r)+ask_right(ch[x][0],L,mid,l,mid));
}
bool check(int x,int a,int b,int c,int d)
{
int sum=ask_left(root[x],1,n,c,d)+ask_right(root[x],1,n,a,b);
if(b+1<c) sum+=ask_all(root[x],1,n,b+1,c-1);
return sum>=0;
}
int main()
{
n=sc();
for(int i=1;i<=n;i++)
h[i].v=sc(),
h[i].pos=i;
sort(h+1,h+n+1,cmp);
build(root[1],1,n);
for(int i=2;i<=n;i++)
add(root[i-1],root[i],1,n,h[i-1].pos,-1);
m=sc();
for(int i=1;i<=m;i++)
{
for(int j=0;j<4;j++)
q[j]=(sc()+ans)%n+1;
sort(q,q+4);
int l=1,r=n;ans=1;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid,q[0],q[1],q[2],q[3]))ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans=h[ans].v);
}
return 0;
}