BZOJ 2653: middle 主席树 二分
https://www.lydsy.com/JudgeOnline/problem.php?id=2653
因为是两个方向向外延伸所以不能对编号取前缀和(这里只有前缀和向后传递的性质,不是实际意义的和),那么对排序后的数字取前缀和,线段树维护编号然后二分就可以了。
在一个值相对的线段树中,数小于该值的位置视为-1,数大于等于该值的位置视为+1. 那么当可取的区间内可以的到的最大的和>=0时该数就是合法的。
维护lmx, rmx, sum三个值分别表示该区间从左向右能得到的最大前缀和、从右向左能得到的最大前缀和、区间和。
二分到区间没有的数也没有关系,二分终究会收敛到区间中存在的数。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 #define LL long long 8 #define pa pair<int,int> 9 const int maxn=20010; 10 pa a[maxn]; 11 int n,m; 12 int q[5]={}; 13 int rt[maxn]={}; 14 int siz[maxn*20]={},lmx[maxn*20]={},rmx[maxn*20]={},lc[maxn*20]={},rc[maxn*20]={},tot=0; 15 inline void updata(int x){ 16 siz[x]=siz[lc[x]]+siz[rc[x]]; 17 lmx[x]=max(lmx[lc[x]],siz[lc[x]]+lmx[rc[x]]); 18 rmx[x]=max(rmx[rc[x]],siz[rc[x]]+rmx[lc[x]]); 19 } 20 void build(int &x,int l,int r){ 21 x=++tot; siz[x]=lmx[x]=rmx[x]=(r-l+1); 22 if(l==r)return; 23 int mid=(l+r)/2; 24 build(lc[x],l,mid); 25 build(rc[x],mid+1,r); 26 } 27 void inser(int &x,int y,int l,int r,int z){ 28 x=++tot;siz[x]=siz[y];lmx[x]=lmx[y];rmx[x]=rmx[y];lc[x]=lc[y];rc[x]=rc[y]; 29 if(l==r){siz[x]=-1;lmx[x]=0;rmx[x]=0;return;} 30 int mid=(l+r)/2; 31 if(z<=mid) inser(lc[x],lc[y],l,mid,z); 32 else inser(rc[x],rc[y],mid+1,r,z); 33 updata(x); 34 } 35 int getsum(int x,int l,int r,int zl,int zr){ 36 if(zl>zr)return 0; 37 if(zl<=l&&r<=zr){return siz[x];} 38 int mid=(l+r)/2,ans=0; 39 if(zl<=mid)ans=getsum(lc[x],l,mid,zl,zr); 40 if(mid<zr)ans+=getsum(rc[x],mid+1,r,zl,zr); 41 return ans; 42 } 43 int getl(int x,int l,int r,int zl,int zr){ 44 if(zl>zr)return 0; 45 if(zl<=l&&r<=zr)return lmx[x]; 46 int mid=(l+r)/2,ans=0; 47 if(zl<=mid)ans=getl(lc[x],l,mid,zl,zr); 48 if(mid<zr)ans=max(ans,getl(rc[x],mid+1,r,zl,zr)+getsum(lc[x],l,mid,zl,mid)); 49 return ans; 50 } 51 int getr(int x,int l,int r,int zl,int zr){ 52 if(zl>zr)return 0; 53 if(zl<=l&&r<=zr)return rmx[x]; 54 int mid=(l+r)/2,ans=0; 55 if(mid<zr)ans=getr(rc[x],mid+1,r,zl,zr); 56 if(zl<=mid)ans=max(ans,getr(lc[x],l,mid,zl,zr)+getsum(rc[x],mid+1,r,mid+1,zr)); 57 return ans; 58 } 59 bool check(int x){ 60 int z=getsum(rt[x],1,n,q[1],q[2]);//cout<<z<<endl; 61 int w=getl(rt[x],1,n,q[2]+1,q[3]);//cout<<w<<endl; 62 int k=getr(rt[x],1,n,q[0],q[1]-1);//cout<<k<<endl; 63 if(z+w+k>=0)return 1; 64 else return 0; 65 } 66 inline int find(){ 67 int l=1,r=n,mid; 68 while(l<r){ 69 mid=(l+r+1)/2; 70 if(check(mid))l=mid; 71 else r=mid-1; 72 }return l; 73 } 74 int main(){ 75 scanf("%d",&n); 76 int x; 77 for(int i=1;i<=n;i++){ scanf("%d",&x); a[i]=make_pair(x,i); } 78 sort(a+1,a+1+n);build(rt[1],1,n); 79 for(int i=2;i<=n;i++){ rt[i]=rt[i-1];inser(rt[i],rt[i],1,n,a[i-1].second); } 80 int ans=0;scanf("%d",&m); 81 for(int i=1;i<=m;i++){ 82 scanf("%d%d%d%d",&q[0],&q[1],&q[2],&q[3]); 83 q[0]=(q[0]+ans)%n+1;q[1]=(q[1]+ans)%n+1; 84 q[2]=(q[2]+ans)%n+1;q[3]=(q[3]+ans)%n+1; 85 sort(q,q+4);ans=a[find()].first; 86 printf("%d\n",ans); 87 } 88 return 0; 89 }