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]。
输入保证满足条件。
第一行所谓“排过序”指的是从小到大排序!
n<=20000,Q<=25000
Output
Q行依次给出询问的答案。
思路:
对于每次询问,二分一个答案,判断是否可行。若大于等于这个数字
的位置标为1,否则标为0,即查询a~b的右连续子区间加上b+1~c-1 的整段区间,在加上c~d的左连续区间的最大值
是否大于等于0。可以用主席树维护每一个状态的0和1的信息。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=20005;
struct node
{
int v,id;
}c[maxn];
int L[maxn*20],R[maxn*20],sum[maxn*20],ls[maxn*20],rs[maxn*20];
bool cmp(const node &a,const node &b) {return a.v<b.v;}
int tol,n,T[maxn],p[5];
void push_up(int rt)
{
sum[rt]=sum[L[rt]]+sum[R[rt]];
ls[rt]=max(ls[L[rt]],sum[L[rt]]+ls[R[rt]]);
rs[rt]=max(rs[R[rt]],sum[R[rt]]+rs[L[rt]]);
}
int build(int l,int r)
{
int rt=++tol;
if(l==r)
{
sum[rt]=ls[rt]=rs[rt]=1;
return rt;
}
int mid=(l+r)/2;
L[rt]=build(l,mid);
R[rt]=build(mid+1,r);
push_up(rt);
return rt;
}
int update(int pre,int l,int r,int pos)
{
int rt=++tol;
L[rt]=L[pre];R[rt]=R[pre];
if(l==r)
{
sum[rt]=ls[rt]=rs[rt]=-1;
return rt;
}
int mid=(l+r)/2;
if(pos<=mid) L[rt]=update(L[pre],l,mid,pos);
else R[rt]=update(R[pre],mid+1,r,pos);
push_up(rt);
return rt;
}
int query1(int rt,int ll,int rr,int l,int r)
{
if(l>=ll&&r<=rr) return sum[rt];
int mid=(l+r)/2;
int ans=0;
if(ll<=mid) ans+=query1(L[rt],ll,rr,l,mid);
if(rr>mid) ans+=query1(R[rt],ll,rr,mid+1,r);
return ans;
}
int query2(int rt,int ll,int rr,int l,int r)
{
if(l>=ll&&r<=rr) return ls[rt];
int mid=(l+r)/2;
if(ll<=mid&&rr>mid) return max(query2(L[rt],ll,rr,l,mid),query1(L[rt],ll,rr,l,mid)+query2(R[rt],ll,rr,mid+1,r));
if(ll<=mid) return query2(L[rt],ll,rr,l,mid);
if(rr>mid) query2(R[rt],ll,rr,mid+1,r);
}
int query3(int rt,int ll,int rr,int l,int r)
{
if(l>=ll&&r<=rr) return rs[rt];
int mid=(l+r)/2;
if(ll<=mid&&rr>mid) return max(query3(R[rt],ll,rr,mid+1,r),query1(R[rt],ll,rr,mid+1,r)+query3(L[rt],ll,rr,l,mid));
if(ll<=mid) return query3(L[rt],ll,rr,l,mid);
if(rr>mid) return query3(R[rt],ll,rr,mid+1,r);
}
bool check(int x,int a,int b,int c,int d)
{
int ans=0;//a=p[0],b=p[1],c=p[2],d=p[3];
if(b+1<c)ans+=query1(T[x],b+1,c-1,1,n);
ans+=query2(T[x],c,d,1,n);
ans+=query3(T[x],a,b,1,n);
return ans>=0;
}
int main()
{
int Q;scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&c[i].v);
c[i].id=i;
}
sort(c+1,c+n+1,cmp);
T[1]=build(1,n);
for(int i=2;i<=n;i++)
T[i]=update(T[i-1],1,n,c[i-1].id);
int x=0;
scanf("%d",&Q);
while(Q--)
{
int x0,x1,x2,x3;scanf("%d%d%d%d",&x0,&x1,&x2,&x3);
p[0]=(x0+x)%n+1;p[1]=(x1+x)%n+1;p[2]=(x2+x)%n+1;p[3]=(x3+x)%n+1;
sort(p,p+4);
int l=1,r=n,i;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid,p[0],p[1],p[2],p[3])) i=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",x=c[i].v);
}
return 0;
}