BZOJ2653: middle
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2653
二分答案。对离散化后的每一个数都建立一棵区间线段树(然后可持久化掉),对于大于等于它的数设为1,否则设为-1 。
然后对于询问只要找(a,b)之间的右起最大和+(c,d)之间的左起最大和+(b+1,c-1)之间的总和≥0就满足否则不满足。
(注意一下如何维护左起最大和,右起最大和。。
#include<cstring> #include<iostream> #include<algorithm> #include<cstdio> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define maxn 50050 #define ll long long using namespace std; struct data{int id,x; }a[maxn]; int sum[maxn*20],lsum[maxn*20],rsum[maxn*20],ls[maxn*20],rs[maxn*20]; int root[maxn]; int n,m,q[5],cnt,ans; int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x*f; } bool cmp(data a,data b){ return a.x<b.x; } void up(int i){ if (i==0) return; sum[i]=sum[ls[i]]+sum[rs[i]]; lsum[i]=max(lsum[ls[i]],sum[ls[i]]+lsum[rs[i]]); rsum[i]=max(rsum[rs[i]],sum[rs[i]]+rsum[ls[i]]); } void build(int &i,int l,int r){ i=++cnt; int mid=(l+r)/2; if (l==r){ sum[i]=lsum[i]=rsum[i]=1; return; } build(ls[i],l,mid); build(rs[i],mid+1,r); up(i); } void add(int l,int r,int x,int &y,int val){ y=++cnt; if (l==r) {sum[y]=lsum[y]=rsum[y]=-1; return;} int mid=(l+r)/2; ls[y]=ls[x]; rs[y]=rs[x]; if (val<=mid) add(l,mid,ls[x],ls[y],val); else add(mid+1,r,rs[x],rs[y],val); up(y); } int qall(int i,int l,int r,int tl,int tr){ if (tl==l&&r==tr) return sum[i]; int mid=(l+r)/2; if (tr<=mid) return qall(ls[i],l,mid,tl,tr); else if (tl>mid) return qall(rs[i],mid+1,r,tl,tr); else return qall(ls[i],l,mid,tl,mid)+qall(rs[i],mid+1,r,mid+1,tr); } int ql(int i,int l,int r,int tl,int tr){ if (tl==l&&r==tr) return lsum[i]; int mid=(l+r)/2; if (tr<=mid) return ql(ls[i],l,mid,tl,tr); else if (tl>mid) return ql(rs[i],mid+1,r,tl,tr); else return max(ql(ls[i],l,mid,tl,mid),qall(ls[i],l,mid,tl,mid)+ql(rs[i],mid+1,r,mid+1,tr)); } int qr(int i,int l,int r,int tl,int tr){ if (tl==l&&r==tr) return rsum[i]; int mid=(l+r)/2; if (tr<=mid) return qr(ls[i],l,mid,tl,tr); else if (tl>mid) return qr(rs[i],mid+1,r,tl,tr); else return max(qall(rs[i],mid+1,r,mid+1,tr)+qr(ls[i],l,mid,tl,mid),qr(rs[i],mid+1,r,mid+1,tr)); } bool jud(int a,int b,int c,int d,int x){ int ans=0; ans=qr(root[x],0,n-1,a,b); ans+=ql(root[x],0,n-1,c,d); if (b+1<c) ans+=qall(root[x],0,n-1,b+1,c-1); if (ans>=0) return 1; return 0; } int main(){ n=read(); rep(i,0,n-1) a[i].x=read(),a[i].id=i; sort(a,a+n,cmp); build(root[0],0,n-1); rep(i,1,n-1) add(0,n-1,root[i-1],root[i],a[i-1].id); m=read(); ans=0; rep(i,1,m){ rep(j,1,4) q[j]=(read()+ans)%n; sort(q+1,q+1+4); int rec=0; int l=0,r=n-1; while (l<=r){ int mid=(l+r)/2; if (jud(q[1],q[2],q[3],q[4],mid)) {rec=mid; l=mid+1;} else r=mid-1; } ans=a[rec].x; printf("%d\n",ans); } return 0; }