BZOJ 2653 middle

题目链接:middle

  首先答案显然是可以二分的,把不小于当前二分的答案的位置设成\(1\),其余位置设为\(-1\),那么就是查询是否存在一段使得和非负。

  对于每个询问我们可以拆成三段,\([a,b]\),\((b,c)\),\([c,d]\)。中间那段显然是要全部统计进去的,所以我们统计一下区间和。前面那段我们需要的是最大后缀和,后面那段我们需要的是最大前缀和。于是建主席树维护就好了。

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define pt(x,l,r) L=l,R=r,D=0,query(rt[x],1,n)
#define maxn 20010
#define MAXN 500010

using namespace std;
typedef long long llg;

int n,m,a[maxn],d[maxn],ld,tt,rt[maxn],q[4],ans,N,D;
int sumv[MAXN],le[MAXN],ri[MAXN],sl[MAXN],sr[MAXN],L,R;
struct data{int x,y;}s[maxn];

int getint(){
	int w=0;bool q=0;
	char c=getchar();
	while((c>'9'||c<'0')&&c!='-') c=getchar();
	if(c=='-') c=getchar(),q=1;
	while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
	return q?-w:w;
}

bool cmp(data x,data y){return x.x<y.x;}
void update(int u,int lc,int lv){
	sumv[u]=sumv[lc]+sumv[lv];
	sl[u]=max(sl[lc],sumv[lc]+sl[lv]);
	sr[u]=max(sr[lv],sumv[lv]+sr[lc]);
}

int build(int l,int r){
	int u=++tt,mid=(l+r)>>1;
	sumv[u]=l-r-1,sl[u]=sr[u]=-1;
	if(l!=r){
		le[u]=build(l,mid);
		ri[u]=build(mid+1,r);
	}
	return u;
}

int add(int u,int l,int r){
	int v=++tt,mid=(l+r)>>1;
	le[v]=le[u];ri[v]=ri[u];
	if(l==r) sl[v]=sr[v]=sumv[v]=1;
	else{
		if(L<=mid) le[v]=add(le[u],l,mid);
		else ri[v]=add(ri[u],mid+1,r);
		update(v,le[v],ri[v]);
	}
	return v;
}

void query(int u,int l,int r){
	int mid=(l+r)>>1;
	if(L<=l && r<=R){
		if(!D) sumv[N]=sumv[u],sl[N]=sl[u],sr[N]=sr[u],D=1;
		else update(N^1,N,u),N^=1; return;
	}
	if(L<=mid) query(le[u],l,mid);
	if(R>mid) query(ri[u],mid+1,r);
}

bool check(int x){
	int now=0;
	if(q[2]-q[1]>1) pt(x,q[1]+1,q[2]-1),now+=sumv[N];
	pt(x,q[0],q[1]); now+=sr[N];
	pt(x,q[2],q[3]); now+=sl[N];
	return now>=0;
}

int main(){
	File("a");
	n=getint();
	for(int i=1;i<=n;i++) d[++ld]=a[i]=getint();
	sort(d+1,d+ld+1); ld=unique(d+1,d+ld+1)-d-1;
	for(int i=1;i<=n;i++) s[i].x=a[i]=lower_bound(d+1,d+ld+1,a[i])-d,s[i].y=i;
	rt[ld+1]=build(1,n); sort(s+1,s+n+1,cmp);
	for(int i=n,o;o=s[i].x,i;i--){
		if(s[i].x!=s[i+1].x) rt[o]=rt[o+1];
		L=R=s[i].y,rt[o]=add(rt[o],1,n);
	}
	m=getint(); N=MAXN-2;
	while(m--){
		for(int i=0;i<4;i++) q[i]=(ans+getint())%n+1;
		sort(q,q+4); ans=0;
		int l=1,r=ld,mid;
		while(l!=r){
			mid=(l+r+1)>>1;
			if(check(mid)) l=mid;
			else r=mid-1;
		}
		printf("%d\n",ans=d[l]);
	}
	return 0;
}
posted @ 2017-03-10 09:26  lcf2000  阅读(186)  评论(1编辑  收藏  举报