传送门
题解
遇到求中位数,一般套路性的方法是二分答案,然后求出该数在区间内的排名,
但是此题稍微有点区别,区间大小不确定,所以我们用到一个更万能的解决中位数问题的套路方法,
设<mid的数为-1,≥mid的数为1,得到b数组,那么若该区间的和S≥0,则该区间中位数≥mid,若S<0,则该区间中位数<mid;
对于的区间,首先区间内的值肯定得加上,然后,要让中位数最大化,也就是让S尽可能大,
所以还要加上内的最大后缀和内的最大前缀,然后判断S正负;
区间和、最大前缀后缀可以用线段树维护,这个简单;
那么b数组怎么求呢?把a数组离散化后,总共有不超过n个mid,对于每个mid都有个不同的b数组,
建n棵线段树?时间空间都过不去;
考虑从到,可以发现只有排名为mid的数会从1变为-1,所以可以用主席树求出每一棵树,复杂度
查询单次复杂度,所以总复杂度。
扫描二维码关注公众号,回复:
12937777 查看本文章
并不需要写3种线段树,因为线段树内维护最大前缀后缀时要用到区间和,所以你可以用一棵线段树维护三个值,方便调用;
查询函数也不需要分别写3个,只需一个函数返回3个值,复杂度都一样,并且这题常数要求并不苛刻(5625000*常数),常数大一点随便过。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
#define ll long long
#define MAXN 20005
using namespace std;
inline ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar();
return f?x:-x;
}
int n,q,IN,root[MAXN],in[5],id;
ll a[MAXN],b[MAXN],ans;
vector<int>c[MAXN];
struct itn{
int ls,rs,s,pr,su;
itn(){}
itn(int L,int R,int S,int P,int U){
ls=L,rs=R,s=S,pr=P,su=U;
}
}t[MAXN*20];
map<ll,int>mp;
inline void build(int x,int l,int r){
if(l==r){t[x].s=t[x].pr=t[x].su=1;return;}
int mid=(l+r)>>1;
t[x].ls=++IN,t[x].rs=++IN;
build(t[x].ls,l,mid),build(t[x].rs,mid+1,r);
t[x].s=t[t[x].ls].s+t[t[x].rs].s;
t[x].pr=max(t[t[x].ls].pr,t[t[x].ls].s+t[t[x].rs].pr);
t[x].su=max(t[t[x].rs].su,t[t[x].rs].s+t[t[x].ls].su);
}
inline void add(int x,int y,int l,int r,int a){
if(l==r){t[x].s=t[x].pr=t[x].su=-1;return;}
int mid=(l+r)>>1;
if(a<=mid)t[x].ls=++IN,t[x].rs=t[y].rs,add(t[x].ls,t[y].ls,l,mid,a);
else t[x].ls=t[y].ls,t[x].rs=++IN,add(t[x].rs,t[y].rs,mid+1,r,a);
t[x].s=t[t[x].ls].s+t[t[x].rs].s;
t[x].pr=max(t[t[x].ls].pr,t[t[x].ls].s+t[t[x].rs].pr);
t[x].su=max(t[t[x].rs].su,t[t[x].rs].s+t[t[x].ls].su);
}
inline itn query(int x,int l,int r,int a,int b){
if(a>b)return itn(a,b,0,0,0);
if(l==a&&r==b)return itn(a,b,t[x].s,t[x].pr,t[x].su);
int mid=(l+r)>>1;
if(a<=mid){
if(b>mid){
itn u=query(t[x].ls,l,mid,a,mid),v=query(t[x].rs,mid+1,r,mid+1,b);
return itn(a,b,u.s+v.s,max(u.pr,u.s+v.pr),max(v.su,v.s+u.su));
}
else return query(t[x].ls,l,mid,a,b);
}
else return query(t[x].rs,mid+1,r,a,b);
}
int main()
{
n=read();
for(int i=1;i<=n;i++)a[i]=read(),mp[a[i]];
map<ll,int>::iterator it;
for(it=mp.begin();it!=mp.end();it++)b[++id]=it->first,it->second=id;
for(int i=1;i<=n;i++)a[i]=mp[a[i]],c[a[i]].push_back(i);
root[1]=++IN,build(IN,1,n);
for(int i=2;i<=id;i++){
root[i]=root[i-1];
for(int j=0;j<c[i-1].size();j++){
int x=++IN;
add(x,root[i],1,n,c[i-1][j]),root[i]=x;
}
}
q=read();
while(q--){
for(int i=0;i<4;i++)in[i]=(read()+ans)%(1ll*n)+1;
sort(in,in+4);
int l=1;
for(int i=15;i>=0;i--)
if(l+(1<<i)<=id){
int o=l+(1<<i),sum=query(root[o],1,n,in[1]+1,in[2]-1).s;
sum+=query(root[o],1,n,in[0],in[1]).su+query(root[o],1,n,in[2],in[3]).pr;
if(sum>-1)l=o;
}
printf("%lld\n",ans=b[l]);
}
return 0;
}