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;
}
posted @ 2019-01-11 09:14  Monster_Qi  阅读(205)  评论(0编辑  收藏  举报