2653: middle
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2294 Solved: 1281
[ Submit][ Status][ Discuss]
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行依次给出询问的答案。
Sample Input
5
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
Sample Output
271451044
271451044
969056313
271451044
969056313
HINT
Source
题解:
打代码的时候各种出锅,调了半天才调好。。。
怎么做
一看到什么中位数,k小数,数据范围又不大,那么就可以二分出一个mid,找出比mid小的个数有多少个。
因为每个数对当前判断的贡献只有是与不是,去或不去,那么用1或-1规划一下就好了。比mid的小的设为-1,否则设为1,那么区间[l…r]中如果中位数为mid那么就是这些1和-1的和加起来≥0。
因为b到c必须要取,所以把区间拆解一下变成[a..b]中的最长后缀和+[a+1…b-1]的和+[c…d]中的最长前缀和。
用什么?
强制在线,那么就是可持久化结构。还支持询问,取max。
可持久化线段树。(PS:即主席树了,可持久化就是主席树的一种应用)
代码:
#include<bits/stdc++.h>
using namespace std;
struct aaa{
int u,v;
}a[100001];
struct bbb{
int sum,ll,rr;
}f[500001];
int tot,n,ls[500001],rs[500001],b[100001],rt[500001],p[5];
bool cmp(aaa a,aaa b){
return a.u<b.u;
}
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;
}
void pushup(int x){
//printf("%d %d %d\n",f[x].sum,f[ls[x]].sum,f[rs[x]].sum);
f[x].sum=f[ls[x]].sum+f[rs[x]].sum;
f[x].ll=max(f[ls[x]].ll,f[ls[x]].sum+f[rs[x]].ll);
f[x].rr=max(f[rs[x]].rr,f[rs[x]].sum+f[ls[x]].rr);
}
void build(int &x,int l,int r){
x=++tot;
if(l==r){
f[x].sum=f[x].ll=f[x].rr=1;
return;
}
int mid=(l+r)/2;
build(ls[x],l,mid);
build(rs[x],mid+1,r);
pushup(x);
}
void update(int &x,int l,int r,int la,int t,int k){
x=++tot;
f[x]=f[la];
ls[x]=ls[la];rs[x]=rs[la];
//printf("%d %d %d %d %d %d %d\n",x,l,r,t,k,la,f[x].sum);
if(l==r){
f[x].sum=f[x].ll=f[x].rr=-1;
return;
}
int mid=(l+r)/2;
if(t<=mid)update(ls[x],l,mid,ls[la],t,k);
else update(rs[x],mid+1,r,rs[la],t,k);
//printf("%d %d %d %d %d %d %d\n",x,l,r,t,k,la,f[x].sum);
pushup(x);
//printf("%d %d %d %d %d %d %d\n",x,l,r,t,k,la,f[x].sum);
}
int querym(int x,int l,int r,int t,int k){
//printf("%d %d %d %d %d %d\n",x,l,r,t,k,f[x].sum);
if(t>k)return 0;
if(l==t&&r==k)return f[x].sum;
int mid=(l+r)/2;
if(mid>=k)return querym(ls[x],l,mid,t,k);
else if(t>mid)return querym(rs[x],mid+1,r,t,k);
else return querym(ls[x],l,mid,t,mid)+querym(rs[x],mid+1,r,mid+1,k);
}
int queryl(int x,int l,int r,int t,int k){
//printf("%d %d %d %d %d %d\n",x,l,r,t,k,f[x].rr);
if(l==t&&r==k)return f[x].rr;
int mid=(l+r)/2;
if(mid>=k)return queryl(ls[x],l,mid,t,k);
else if(t>mid)return queryl(rs[x],mid+1,r,t,k);
else{
int le=queryl(ls[x],l,mid,t,mid),ri=queryl(rs[x],mid+1,r,mid+1,k),sum=querym(rs[x],mid+1,r,mid+1,k);
return max(ri,sum+le);
}
}
int queryr(int x,int l,int r,int t,int k){
if(l==t&&r==k)return f[x].ll;
int mid=(l+r)/2;
if(mid>=k)return queryr(ls[x],l,mid,t,k);
else if(t>mid)return queryr(rs[x],mid+1,r,t,k);
else{
int le=queryr(ls[x],l,mid,t,mid),ri=queryr(rs[x],mid+1,r,mid+1,k),sum=querym(ls[x],l,mid,t,mid);
return max(le,sum+ri);
}
}
int pd(int x){
//printf("%d %d %d %d\n",x,p[2]+1,p[3]-1,querym(rt[x],1,n,p[2]+1,p[3]-1));
int sum=queryl(rt[x],1,n,p[1],p[2])+querym(rt[x],1,n,p[2]+1,p[3]-1)+queryr(rt[x],1,n,p[3],p[4]);
//printf("%d\n",sum);
return sum;
}
int main(){
int i,l,r,mid,ans,la,m;
scanf("%d",&n);
for(i=1;i<=n;i++){
a[i].u=read();
a[i].v=i;
}
sort(a+1,a+n+1,cmp);
build(rt[1],1,n);
for(i=2;i<=n;i++)update(rt[i],1,n,rt[i-1],a[i-1].v,-1);
scanf("%d",&m);
//printf("%d\n",f[rt[2]].sum);
la=0;
while(m--){
for(i=1;i<=4;i++){
p[i]=read();
p[i]=(p[i]+la)%n+1;
}
sort(p+1,p+5);
//for(i=1;i<=4;i++)printf("%d ",p[i]);
//puts("");
l=1;r=n;ans=0;
while(l<=r){
mid=(l+r)/2;
if(pd(mid)>=0){
ans=max(ans,mid);
l=mid+1;
}
else r=mid-1;
}
printf("%d\n",a[ans].u);
la=a[ans].u;
}
}