[国家集训队]Middle
Description:
一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。
给你一个长度为n的序列s。
回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a<b<c<d。
位置也从0开始标号。
我会使用一些方式强制你在线。
Hint:
\(n,q \le 5*10^4\)
Solution:
正解方法很简单,但真的很难想
区间不确定,无法直接找中位数,考虑二分答案
每次把大于等于该数的位置赋为1,其余赋为-1
然后加上[b+1,c-1]的和,[c,d]的最大前缀和以及[a,b]的最大后缀和(这样一定能保证选到限制区间中的最优区间)
看是否大于等于0就行
由于二分的单调性,我们只需从小到大依次把每个数从-1修改为1,考虑主席树
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mxn=1e6+5;
int n,m,s,cnt,tot,q[6],hd[mxn];
int a[mxn],b[mxn],rk[mxn],rt[mxn<<6],ls[mxn<<6],rs[mxn<<6],lmx[mxn<<6],rmx[mxn<<6],sum[mxn<<6];
inline int read() {
char c=getchar(); int x=0,f=1;
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
return x*f;
}
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}
struct ed {
int to,nxt;
}t[mxn<<1];
inline void add(int u,int v) {
t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
}
int cmp(int x,int y) {
return a[x]<a[y];
}
void build(int l,int r,int &p) {
if(!p) p=++tot;
if(l==r) {
sum[p]=lmx[p]=rmx[p]=1;
return ;
}
int mid=(l+r)>>1;
build(l,mid,ls[p]); build(mid+1,r,rs[p]);
sum[p]=sum[ls[p]]+sum[rs[p]];
lmx[p]=max(lmx[ls[p]],sum[ls[p]]+lmx[rs[p]]);
rmx[p]=max(rmx[rs[p]],sum[rs[p]]+rmx[ls[p]]);
}
void update(int las,int &p,int l,int r,int pos) {
if(!p) p=++tot;
if(l==r) {
sum[p]=lmx[p]=rmx[p]=-1;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) update(ls[las],ls[p],l,mid,pos),rs[p]=rs[las];
else update(rs[las],rs[p],mid+1,r,pos),ls[p]=ls[las];
sum[p]=sum[ls[p]]+sum[rs[p]];
lmx[p]=max(lmx[ls[p]],sum[ls[p]]+lmx[rs[p]]);
rmx[p]=max(rmx[rs[p]],sum[rs[p]]+rmx[ls[p]]);
}
int query(int l,int r,int ql,int qr,int p) {
if(ql<=l&&r<=qr) return sum[p];
int mid=(l+r)>>1; int res=0;
if(ql<=mid) res+=query(l,mid,ql,qr,ls[p]);
if(qr>mid) res+=query(mid+1,r,ql,qr,rs[p]);
return res;
}
int querylmx(int l,int r,int ql,int qr,int p) {
if(ql<=l&&r<=qr) return lmx[p];
int mid=(l+r)>>1;
if(qr<=mid) return querylmx(l,mid,ql,qr,ls[p]);
else if(ql>mid) return querylmx(mid+1,r,ql,qr,rs[p]);
else return max(querylmx(l,mid,ql,qr,ls[p]),query(l,mid,ql,qr,ls[p])+querylmx(mid+1,r,ql,qr,rs[p]));
}
int queryrmx(int l,int r,int ql,int qr,int p) {
if(ql<=l&&r<=qr) return rmx[p];
int mid=(l+r)>>1;
if(qr<=mid) return queryrmx(l,mid,ql,qr,ls[p]);
else if(ql>mid) return queryrmx(mid+1,r,ql,qr,rs[p]);
else return max(queryrmx(mid+1,r,ql,qr,rs[p]),query(mid+1,r,ql,qr,rs[p])+queryrmx(l,mid,ql,qr,ls[p]));
}
int check(int id,int x,int y,int w,int z) {
int res=0;
if(y+1<=w-1) res+=query(1,n,y+1,w-1,rt[id]);
res+=querylmx(1,n,w,z,rt[id]); res+=queryrmx(1,n,x,y,rt[id]);
return res>=0;
}
int main()
{
n=read(); int ans=0;
for(int i=1;i<=n;++i) a[i]=b[i]=read(),rk[i]=i;
sort(b+1,b+n+1);
for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+n+1,a[i])-b;
sort(rk+1,rk+n+1,cmp); build(1,n,rt[1]);
for(int i=2;i<=n;++i) update(rt[i-1],rt[i],1,n,rk[i-1]);
m=read();
for(int i=1;i<=m;++i) {
for(int j=1;j<=4;++j) q[j]=(read()+ans)%n;
sort(q+1,q+5);
int l=1,r=n;
while(l<r) {
int mid=(l+r+1)>>1;
if(check(mid,q[1]+1,q[2]+1,q[3]+1,q[4]+1)) l=mid;
else r=mid-1;
}
printf("%d\n",ans=b[l]);
}
return 0;
}