【BZOJ2653】【洛谷2839】—Middle(主席树+二分答案)
这种题为什么会在我谷上黑题啊?有毒吧
想起一道相似的题【HEOI2016/TJOI2016】排序
而这道题是要求最大中位数
我们考虑二分一个数
将所有小于的赋为,其余赋为
那也就是说如果我们能在~, ~之间选一段区间使其和
那么我们的下界显然就可以调高
那问题就变成了怎么求这一段的最大子段和
考虑到+~-之间是必须要的选的
~选靠右的最大子段, ~选靠左的最大子段
用线段树维护一下区间和,区间最大左段、右段和就可以了
那么现在剩下的问题就是怎么构建线段树
如果每次询问都构建的话显然复杂度是的
我们考虑到如果从小到大,显然线段树中是单调的不断有点从变成
那显然一共只有种可能的线段树,而且它们相互只有一个节点不一样
那改成主席树就可以了
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=20005;
struct Seg{
int sum,l,r,lson,rson;
Seg(int a=0):sum(a),l(a),r(a),lson(a),rson(a){}
friend inline Seg operator +(const Seg&a,const Seg&b){
Seg res;res.sum=a.sum+b.sum;
res.l=max(a.l,a.sum+b.l),res.r=max(b.r,a.r+b.sum);
return res;
}
}tr[N<<2];
struct pc{
int val,pos;
}a[N];
inline bool comp(const pc&a,const pc&b){
return a.val<b.val;
}
int rt[N],q[5],ans,n,m,tot;
#define lc tr[u].lson
#define rc tr[u].rson
#define mid ((l+r)>>1)
inline void pushup(int u){
tr[u].sum=tr[lc].sum+tr[rc].sum;
tr[u].l=max(tr[lc].l,tr[lc].sum+tr[rc].l);
tr[u].r=max(tr[rc].r,tr[lc].r+tr[rc].sum);
}
void buildtree(int &u,int l,int r){
u=++tot;
if(l==r){tr[u].sum=tr[u].l=tr[u].r=1;return;}
buildtree(lc,l,mid);
buildtree(rc,mid+1,r);
pushup(u);
}
void update(int &u,int r1,int l,int r,int p){
u=++tot,tr[u]=tr[r1];
if(l==r){tr[u].sum=tr[u].l=tr[u].r=-1;return;}
if(p<=mid)update(lc,tr[r1].lson,l,mid,p);
else update(rc,tr[r1].rson,mid+1,r,p);
pushup(u);
}
Seg query(int u,int l,int r,int st,int des){
if(st<=l&&r<=des)return tr[u];
if(des<=mid)return query(lc,l,mid,st,des);
if(mid<st)return query(rc,mid+1,r,st,des);
return query(lc,l,mid,st,des)+query(rc,mid+1,r,st,des);
}
inline bool check(int k,int a,int b,int c,int d){
int res=0;
if(b+1<=c-1)res+=query(rt[k],0,n-1,b+1,c-1).sum;
res+=query(rt[k],0,n-1,a,b).r;
res+=query(rt[k],0,n-1,c,d).l;
return res>=0;
}
#undef mid
signed main(){
n=read();
for(int i=0;i<n;i++)a[i].val=read(),a[i].pos=i;
sort(a,a+n,comp);
buildtree(rt[0],0,n-1);
for(int i=1;i<n;i++)update(rt[i],rt[i-1],0,n-1,a[i-1].pos);
m=read();
for(int i=1;i<=m;i++){
q[1]=(read()+ans)%n,q[2]=(read()+ans)%n,q[3]=(read()+ans)%n,q[4]=(read()+ans)%n;
sort(q+1,q+5);
int l=0,r=n-1,p=0;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid,q[1],q[2],q[3],q[4]))l=mid+1,p=mid;
else r=mid-1;
}
cout<<(ans=a[p].val)<<'\n';
}
}