Description
一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。给你一个
长度为n的序列s。回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a< b < c < d。位置也从0开始标号。我会使用一些方式强制你在线。
Input
第一行序列长度n。接下来n行按顺序给出a中的数。
接下来一行Q。然后Q行每行a,b,c,d,我们令上个询问的答案是
x(如果这是第一个询问则x=0)。
令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
将q从小到大排序之后,令真正的
要询问的a=q[0],b=q[1],c=q[2],d=q[3]。
输入保证满足条件。
第一行所谓“排过序”指的是从大到小排序!
Output
Q行依次给出询问的答案。
Sample Input
5
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
271451044
271451044
969056313
Sample Output
HINT
0:n,Q<=100
1,…,5:n<=2000
0,…,19:n<=20000,Q<=25000
题解
二分答案+可持久化线段树
对于每个数值,建立一颗线段树,比它小的数(记为-1)比它大的数(记为+1),记录区间和,左/右区间最大字段和。
二分中位数,去可持久化线段树中判断是否有更大的中位数。
代码
#include<bits/stdc++.h>
#define mod 1000000007
#define inf 1000000005
#define N 20005
typedef long long ll;
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct node{int v,p;}a[N];
int tot,q[5],rt[N],ls[N*20],rs[N*20],sum[N*20],L[N*20],R[N*20],n,lastans;
bool cmp(node a,node b){return a.v<b.v;}
void update(int k)
{
sum[k]=sum[ls[k]]+sum[rs[k]];
L[k]=max(L[ls[k]],sum[ls[k]]+L[rs[k]]);
R[k]=max(R[rs[k]],sum[rs[k]]+R[ls[k]]);
}
void build(int &k,int l,int r)
{
k=++tot;
if (l==r){sum[k]=L[k]=R[k]=1;return;}
int mid=(l+r)>>1;
build(ls[k],l,mid);build(rs[k],mid+1,r);
update(k);
}
void insert(int &k1,int k2,int l,int r,int v)
{
k1=++tot;
ls[k1]=ls[k2];rs[k1]=rs[k2];
if (l==r){sum[k1]=L[k1]=R[k1]=-1;return;}
int mid=(l+r)>>1;
if (v<=mid) insert(ls[k1],ls[k2],l,mid,v);
else insert(rs[k1],rs[k2],mid+1,r,v);
update(k1);
}
int que1(int k,int l,int r,int x,int y)
{
if (l==x&&r==y) return sum[k];
int mid=(l+r)>>1;
if (y<=mid) return que1(ls[k],l,mid,x,y);
else if (x>mid) return que1(rs[k],mid+1,r,x,y);
else return que1(ls[k],l,mid,x,mid)+que1(rs[k],mid+1,r,mid+1,y);
}
int que2(int k,int l,int r,int x,int y)
{
if (l==x&&r==y) return R[k];
int mid=(l+r)>>1;
if (y<=mid) return que2(ls[k],l,mid,x,y);
else if (x>mid) return que2(rs[k],mid+1,r,x,y);
else return max(que2(rs[k],mid+1,r,mid+1,y),que1(rs[k],mid+1,r,mid+1,y)+que2(ls[k],l,mid,x,mid));
}
int que3(int k,int l,int r,int x,int y)
{
if (l==x&&r==y) return L[k];
int mid=(l+r)>>1;
if (y<=mid) return que3(ls[k],l,mid,x,y);
else if (x>mid) return que3(rs[k],mid+1,r,x,y);
else return max(que3(ls[k],l,mid,x,mid),que1(ls[k],l,mid,x,mid)+que3(rs[k],mid+1,r,mid+1,y));
}
bool judge(int mid,int a,int b,int c,int d)
{
int ans=0;
if (c-b>1) ans+=que1(rt[mid],1,n,b+1,c-1);
ans+=que2(rt[mid],1,n,a,b);
ans+=que3(rt[mid],1,n,c,d);
return ans>=0;
}
int main()
{
n=read();
for (int i=1;i<=n;i++) a[i].v=read(),a[i].p=i;
sort(a+1,a+n+1,cmp);
build(rt[1],1,n);
for (int i=2;i<=n;i++) insert(rt[i],rt[i-1],1,n,a[i-1].p);
int Case=read(),lastans=0;
while (Case--)
{
q[0]=(read()+lastans)%n+1;
q[1]=(read()+lastans)%n+1;
q[2]=(read()+lastans)%n+1;
q[3]=(read()+lastans)%n+1;
sort(q,q+4);
int l=1,r=n;
while (l!=r)
{
int mid=(l+r+1)>>1;
if (judge(mid,q[0],q[1],q[2],q[3])) l=mid;else r=mid-1;
}
lastans=a[l].v;
printf("%d\n",lastans);
}
return 0;
}