【BZOJ2653】【洛谷2839】—Middle(主席树+二分答案)

BZOJ传送门

洛谷

这种题为什么会在我谷上黑题啊?有毒吧

想起一道相似的题【HEOI2016/TJOI2016】排序

而这道题是要求最大中位数

我们考虑二分一个数midmid

将所有小于midmid的赋为1-1,其余赋为11

那也就是说如果我们能在aa~bb, cc~dd之间选一段区间使其和sum>=0sum>=0

那么我们的下界显然就可以调高

那问题就变成了怎么求这一段的最大子段和

考虑到bb+11~cc-11之间是必须要的选的

aa~bb选靠右的最大子段, cc~dd选靠左的最大子段

用线段树维护一下区间和,区间最大左段、右段和就可以了

那么现在剩下的问题就是怎么构建线段树

如果每次询问都构建的话显然复杂度是O(n2logn)O(n^2logn)

我们考虑到如果midmid从小到大,显然线段树中是单调的不断有点从11变成1-1

那显然一共只有nn种可能的线段树,而且它们相互只有一个节点不一样

那改成主席树就可以了

#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';
	}
}
posted @ 2019-01-24 10:25  Stargazer_cykoi  阅读(126)  评论(0编辑  收藏  举报