谈谈这一道题的最强烈的感受在于,我的主席树入门是经典题目区间第k大树查询(当然,因为poj上不会强制在线,还用树套树和整体二分写过那道题),因此,对于主席树的理解仅仅是一个区间历史版本维护的理解,即类似于树套树的外层区间树内层全值树。但是忽略了主席树的真正伟大之处在于可持久化,而可持久化的也能是权值。
对于这一道题,由于我们不知道中位数是多少,因此考虑二分,而关键之处在于如何二分cheak,可以这样,把所有大于这个数的数定义为1,而小于这个数的定义为-1,那么只要一段区间区间和大于等于0就说明当前值是可行的,继续二分,关键就在于如何快速得到一段区间的最大和。最简单的思想是对于每一次的询问,我On的一次处理,把比他大的赋值为1,小的赋值为-1,然后可以利用线段树维护区间最大和得到,然后进一步思考,发现每一次都On赋值肯定受不老,那么思考树套树,对于没一个权值(离散化后)都建立一个区间树,这个树就储存每一个位置是-1,还是1,但是还是受不了,不够思想已经很接近了,我们继续观察可以发现,其实每一个权值对于上一个权值来说的相对状态只有一个数不同,我们先按权值排序,然后主席树的每一个叶子节点都是1(对于最小的数来说其他数都比他大),然后不断插入更大取值的节点,不断更新这个主席树,最后就得到一个类似于外层权值树内层区间树的主席树,不过充分利用了先前的信息,这就是可持久化操作的美妙之处了把。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 20020
#define ll nod[u].ls
#define rr nod[u].rs
#define lc nod[u].ls,l,mid
#define rc nod[u].rs,mid+1,r
using namespace std;
int n,a[maxn],b[maxn],tot,rt[maxn];
struct node{int s,ml,mr,ls,rs;}nod[20020*50];
bool cmp(const int& x,const int& y){return a[x]<a[y];}
void push_up(int u){
nod[u].s=nod[ll].s+nod[rr].s;
nod[u].ml=max(nod[ll].ml,nod[ll].s+nod[rr].ml);
nod[u].mr=max(nod[rr].mr,nod[ll].mr+nod[rr].s);
}
void build(int& u,int l,int r){
u=++tot;nod[u].s=nod[u].ml=nod[u].mr=r-l+1;
if(l==r)return;
int mid=l+r>>1;
build(nod[u].ls,l,mid);build(nod[u].rs,mid+1,r);
}
void update(int x,int& y, int l,int r,int v){
y=++tot;nod[y].ls=nod[x].ls,nod[y].rs=nod[x].rs;
if(l==r){nod[y].ml=nod[y].mr=nod[y].s=-1;return;}
int mid=l+r>>1;
if(v>mid)update(nod[x].rs,nod[y].rs,mid+1,r,v);
else update(nod[x].ls,nod[y].ls,l,mid,v);
push_up(y);
}
int query_sum(int u,int l,int r,int x,int y){
if(l>=x&&r<=y)return nod[u].s;
int mid=l+r>>1;
if(x>mid)return query_sum(rc,x,y);
else if(y<=mid)return query_sum(lc,x,y);
else return query_sum(lc,x,y)+query_sum(rc,x,y);
}
int query_ml(int u,int l,int r,int x,int y){
if(l>=x&&r<=y)return nod[u].ml;
int mid=l+r>>1;
if(x>mid)return query_ml(rc,x,y);
else if(y<=mid)return query_ml(lc,x,y);
else return max(query_ml(lc,x,y),query_sum(lc,x,y)+query_ml(rc,x,y));
}
int query_mr(int u,int l,int r,int x,int y){
if(x<=l&&r<=y)return nod[u].mr;
int mid=l+r>>1;
if(x>mid)return query_mr(rc,x,y);
else if(y<=mid)return query_mr(lc,x,y);
else return max(query_mr(rc,x,y),query_sum(rc,x,y)+query_mr(lc,x,y));
}
int Q,c[5],last,l1,l2,r1,r2;
bool check(int x){
int ans=query_mr(rt[x],1,n,l1,r1)+query_ml(rt[x],1,n,l2,r2);
if(l2>r1+1)ans+=query_sum(rt[x],1,n,r1+1,l2-1);
return ans>=0;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",a+i),b[i]=i;
sort(b+1,b+1+n,cmp);build(rt[0],1,n);
for(int i=1;i<=n;i++)update(rt[i-1],rt[i],1,n,b[i]);
scanf("%d",&Q);
while(Q--){
for(int i=1;i<=4;i++)scanf("%d",c+i),c[i]=(c[i]+last)%n;
sort(c+1,c+5);l1=c[1]+1,r1=c[2]+1,l2=c[3]+1,r2=c[4]+1;
int l=1,r=n,ans;
while(l<r){
int mid=l+r>>1;
if(check(mid))l=mid+1;
else r=mid;
}
printf("%d\n",last=a[b[l]]);
}
return 0;
}