我现在只觉得这题很nb
可以考虑二分答案,把中间小于 m i d mid mid的数设为 − 1 -1 −1,其他的设为 1 1 1,然后查看区间和是否大于 0 0 0,若大于等于 0 0 0,则说明可取,反之,不可取
由于区间端点不是固定的,左端点在一个区间内,右端点在另一个区间内,那么最大前缀就是
l m a x = m a x ( l m a l , s u m l + l m a r ) lma_x=max(lma_l,sum_l+lma_r) lmax=max(lmal,suml+lmar)
那么最大的后缀也是同理
r m a x = m a x ( r m a r , s u m r + r m a l ) rma_x=max(rma_r,sum_r+rma_l) rmax=max(rmar,sumr+rmal)
由于左端点在 [ a , b ] [a,b] [a,b]内,右端点在 [ c , d ] [c,d] [c,d]内,要查询的区间必然存在 [ b , c ] [b,c] [b,c],所以大于等于 0 0 0时才是可取的
为了确保二分的数一定是正确的(即原数组中出现过),可以采取先离散化,后二分的方式,这样就确保二分是一定正确的了
所以现在,问题的难点在于如何把区间的数变为 0 0 0和 1 1 1,考虑从 − 1 -1 −1到 1 1 1的时候,仅当 m i d mid mid从 m i d < b i mid<b_i mid<bi,变到 m i d > = b i mid>=b_i mid>=bi( b i b_i bi是离散化后的数组)时,才会从 − 1 -1 −1变成 1 1 1,每个数的贡献仅仅只会被改变一次。
由于这些数是可以共用的,所以可以使用主席树
#include <bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define int long long
//#define double long double
#define re register int
#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define P pair < int , int >
#define mk make_pair
using namespace std;
const int mod=1e9+7;
const int M=1e8+5;
const int N=1e5+5;//?????????? 4e8
int n,q,m;
int a[N],b[N];
struct node
{
int l,r;
int sum,lma,rma;
}e[N*80];
int rt[N],tot;
int aa,bb,cc,dd;
void push(int p)
{
e[p].sum=e[e[p].l].sum+e[e[p].r].sum;
e[p].lma=max(e[e[p].l].lma,e[e[p].l].sum+e[e[p].r].lma);
e[p].rma=max(e[e[p].r].rma,e[e[p].r].sum+e[e[p].l].rma);
}
void bulid(int &p,int l,int r)
{
p=++tot;
if(l==r)
{
e[p].lma=e[p].sum=e[p].rma=-1;
return;
}
int mid=(l+r)>>1;
bulid(e[p].l,l,mid);bulid(e[p].r,mid+1,r);
push(p);
}
void insert(int &p,int pre,int l,int r,int pos)
{
e[++tot]=e[pre];
p=tot;
if(l==r)
{
e[p].sum=e[p].lma=e[p].rma=1;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) insert(e[p].l,e[pre].l,l,mid,pos);
else insert(e[p].r,e[pre].r,mid+1,r,pos);
push(p);
}
node ask(int p,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return e[p];
int mid=(l+r)>>1;
if(L>mid) return ask(e[p].r,mid+1,r,L,R);
else if(R<=mid) return ask(e[p].l,l,mid,L,R);
else
{
node ans,lson,rson;
lson=ask(e[p].l,l,mid,L,R);
rson=ask(e[p].r,mid+1,r,L,R);
ans.sum=(lson.sum+rson.sum);
ans.lma=max(lson.lma,lson.sum+rson.lma);
ans.rma=max(rson.rma,rson.sum+lson.rma);
return ans;
}
}
bool check(int mid)
{
int res=0;
node ans=ask(rt[mid],1,n,aa,bb);
res+=ans.rma;
if(bb+1<=cc-1) ans=ask(rt[mid],1,n,bb+1,cc-1),res+=ans.sum;
ans=ask(rt[mid],1,n,cc,dd);res+=ans.lma;
return res>=0;
}
bool cmp(int x,int y)
{
return a[x]<a[y];
}
int ans;
void solve()
{
cin>>n;
for(re i=1;i<=n;i++) scanf("%lld",&a[i]),b[i]=i;
sort(b+1,b+n+1,cmp);
bulid(rt[n+1],1,n);
for(re i=n;i>=1;i--) insert(rt[i],rt[i+1],1,n,b[i]);
cin>>q;
while(q--)
{
scanf("%lld%lld%lld%lld",&aa,&bb,&cc,&dd);
aa=(aa+ans)%n+1,bb=(bb+ans)%n+1;
cc=(cc+ans)%n+1,dd=(dd+ans)%n+1;
int t[5]={0,aa,bb,cc,dd};
sort(t+1,t+4+1);
// for(re i=1;i<=4;i++) cout<<t[i]<<" ";puts("");
aa=t[1],bb=t[2],cc=t[3],dd=t[4];
int l=1,r=n,cnt;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)) cnt=mid,l=mid+1;
else r=mid-1;
}
ans=a[b[cnt]];
printf("%lld\n",ans);
}
}
signed main()
{
int T=1;
// cin>>T;
for(int index=1;index<=T;index++)
{
// printf("Case %d:\n",index);
solve();
// puts("");
}
return 0;
}
/*
1
6 5
0 0 0 122 499 8888
*/