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; }