BZOJ 2653: middle(主席树+二分答案)
解题思路
首先可以想到一种暴力做法,就是询问时二分,然后大于等于这个值的设为1,否则设为-1,然后就和GSS1那样统计答案。但是发现这样时间空间复杂度都很爆炸,所以考虑预处理,可以用主席树来做了。以\(rt[i]\)为根线段树维护二分的答案为\(i\)的线段树,线段树下标是位置。处理的时候就排一遍序,然后每次\(mid+1\)的时候发现只有\(mid\)这个位置的值要变成\(-1\),所以可以直接处理。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=20005;
const int M=N*20;
template<class T> void rd(T &x){
x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
}
inline int qmax(int x,int y){return x>y?x:y;}
int n,m,a[N],id[N],lx[M],rx[M],sum[M],ls[M],rs[M],tot,rt[N];
int q[10];
inline bool cmp(int x,int y){return a[x]<a[y];}
void build(int &x,int l,int r){
x=++tot;int mid=(l+r)>>1;
if(l==r) {sum[x]=lx[x]=rx[x]=1;return ;}
build(ls[x],l,mid);build(rs[x],mid+1,r);
sum[x]=sum[ls[x]]+sum[rs[x]];
lx[x]=rx[x]=sum[x];
}
void update(int pre,int &x,int l,int r,int k){
x=++tot;sum[x]=sum[pre];rx[x]=rx[pre];
ls[x]=ls[pre];rs[x]=rs[pre];lx[x]=lx[pre];
if(l==r) {lx[x]=rx[x]=sum[x]=-1;return ;}
int mid=(l+r)>>1;
if(k<=mid) update(ls[pre],ls[x],l,mid,k);
else update(rs[pre],rs[x],mid+1,r,k);
sum[x]=sum[ls[x]]+sum[rs[x]];
lx[x]=qmax(lx[ls[x]],sum[ls[x]]+lx[rs[x]]);
rx[x]=qmax(rx[rs[x]],sum[rs[x]]+rx[ls[x]]);
}
int query_sum(int x,int l,int r,int L,int R){
if(L>R) return 0;
if(L<=l && r<=R) return sum[x];
int mid=(l+r)>>1,ret=0;
if(L<=mid) ret+=query_sum(ls[x],l,mid,L,R);
if(mid<R) ret+=query_sum(rs[x],mid+1,r,L,R);
return ret;
}
int query_lx(int x,int l,int r,int L,int R){
if(L<=l && r<=R) return lx[x];
int mid=(l+r)>>1;
if(L>mid) return query_lx(rs[x],mid+1,r,L,R);
else if(mid>=R) return query_lx(ls[x],l,mid,L,R);
else return qmax(query_lx(ls[x],l,mid,L,R),query_sum(ls[x],l,mid,L,R)+query_lx(rs[x],mid+1,r,L,R));
}
int query_rx(int x,int l,int r,int L,int R){
if(L<=l && r<=R) return rx[x];
int mid=(l+r)>>1;
if(L>mid) return query_rx(rs[x],mid+1,r,L,R);
else if(mid>=R) return query_rx(ls[x],l,mid,L,R);
else return qmax(query_rx(rs[x],mid+1,r,L,R),query_sum(rs[x],mid+1,r,L,R)+query_rx(ls[x],l,mid,L,R));
}
inline bool check(int lim){
int ret=0;
ret+=query_sum(rt[lim],1,n,q[2]+1,q[3]-1);
ret+=query_lx(rt[lim],1,n,q[3],q[4]);
ret+=query_rx(rt[lim],1,n,q[1],q[2]);
return ret>=0?1:0;
}
int main(){
rd(n);int lstans=0;
for(int i=1;i<=n;i++) rd(a[i]),id[i]=i;
sort(id+1,id+1+n,cmp);build(rt[1],1,n);sort(a+1,a+1+n);
for(int i=2;i<=n+1;i++) update(rt[i-1],rt[i],1,n,id[i-1]);
for(rd(m);m;m--){
rd(q[1]);rd(q[2]);rd(q[3]);rd(q[4]);
q[1]=(q[1]+lstans)%n+1;q[2]=(q[2]+lstans)%n+1;
q[3]=(q[3]+lstans)%n+1;q[4]=(q[4]+lstans)%n+1;
sort(q+1,q+1+4);int L=1,R=n,mid;
while(L<=R){
mid=(L+R)>>1;
if(check(mid)) lstans=mid,L=mid+1;
else R=mid-1;
}
printf("%d\n",a[lstans]);lstans=a[lstans];
}
return 0;
}