bzoj 2653 二分+主席树
2016-10-21 08:53
417 查看
这个东西可以二分答案,设当前答案为x,那么将序列中大于等于x的数设为1,小于x的数设为-1。
这样如果一个区间的和≥0,那么这段区间的中位数≥x。、
因此只需要求最大连续子段和是否大于等于0就可以了。
最大连续子段和可以用线段树求。
不过对于每一个二分的答案都需要一个线段树。
由于当答案增加时线段树上只有一个点的值改变,因此可以用可持久化线段树维护。
这样如果一个区间的和≥0,那么这段区间的中位数≥x。、
因此只需要求最大连续子段和是否大于等于0就可以了。
最大连续子段和可以用线段树求。
不过对于每一个二分的答案都需要一个线段树。
由于当答案增加时线段树上只有一个点的值改变,因此可以用可持久化线段树维护。
#include <bits/stdc++.h> using namespace std; #define N 21000 #define M 3100000 #define ll long long int n,cnt,Q,ans,top; int a ,root ,q[5]; pair<int,int>b ; int ch[M][2],mx[M],ml[M],mr[M],sum[M]; int st[110]; void build(int l,int r,int &now) { now=++cnt; mx[now]=ml[now]=mr[now]=sum[now]=r-l+1; if(l==r)return; int mid=(l+r)>>1; build(l,mid,ch[now][0]); build(mid+1,r,ch[now][1]); } void pushup(int x) { int ls=ch[x][0],rs=ch[x][1]; mx[x]=max(max(mx[ls],mx[rs]),mr[ls]+ml[rs]); ml[x]=max(ml[ls],sum[ls]+ml[rs]); mr[x]=max(mr[rs],sum[rs]+mr[ls]); sum[x]=sum[ls]+sum[rs]; } void insert(int l,int r,int pre,int &now,int pos) { now=++cnt; if(l==r) { mx[now]=ml[now]=mr[now]=sum[now]=-1; return; } int mid=(l+r)>>1; ch[now][0]=ch[pre][0]; ch[now][1]=ch[pre][1]; if(mid>=pos)insert(l,mid,ch[pre][0],ch[now][0],pos); else insert(mid+1,r,ch[pre][1],ch[now][1],pos); pushup(now); } int getsum(int l,int r,int now,int lq,int rq) { if(lq<=l&&r<=rq)return sum[now]; int mid=(l+r)>>1,ret=0; if(mid>=lq)ret+=getsum(l,mid,ch[now][0],lq,rq); if(mid<rq) ret+=getsum(mid+1,r,ch[now][1],lq,rq); return ret; } void find(int l,int r,int now,int lq,int rq) { if(lq<=l&&r<=rq) {st[++top]=now;return;} int mid=(l+r)>>1; if(mid>=lq)find(l,mid,ch[now][0],lq,rq); if(mid<rq) find(mid+1,r,ch[now][1],lq,rq); } int check(int x) { int sm=getsum(1,n,root[x],q[2],q[3]),sl=0,sr=0; top=0;find(1,n,root[x],q[1],q[2]-1); for(int i=top,t=0;i>=1;i--) { sl=max(sl,t+mr[st[i]]); t+=sum[st[i]]; } top=0;find(1,n,root[x],q[3]+1,q[4]); for(int i=1,t=0;i<=top;i++) { sr=max(sr,t+ml[st[i]]); t+=sum[st[i]]; } return sl+sm+sr>=0; } int main() { //freopen("tt.in","r",stdin); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=make_pair(a[i],i); sort(b+1,b+1+n); build(1,n,root[1]); for(int i=2;i<=n;i++) insert(1,n,root[i-1],root[i],b[i-1].second); scanf("%d",&Q); for(;Q--;) { for(int i=1;i<=4;i++) scanf("%d",&q[i]),q[i]=((ll)q[i]+ans)%n+1; sort(q+1,q+1+4); int l=1,r=n; while(l<=r) { int mid=(l+r)>>1; if(check(mid))l=mid+1; else r=mid-1; } printf("%d\n",ans=b[r].first); } return 0; }
相关文章推荐
- 【bzoj2653】【middle】【主席树+二分答案】
- [BZOJ2653] middle - 主席树(可持久化线段树) - 二分
- [bzoj2653][middle] (二分 + 主席树)
- BZOJ2653 middle 【二分 + 主席树】
- bzoj 2653 middle 二分答案 主席树判定
- bzoj 2653(主席树+二分)
- BZOJ2653 middle(二分答案+主席树)
- [BZOJ2653]middle 主席树+二分
- 【BZOJ2653】middle(主席树,二分)
- bzoj 2653: middle (二分+主席树)
- 【BZOJ2653】middle,主席树(非权值线段树)维护序列和信息+二分答案
- [BZOJ2653]middle(主席树+二分)
- Bzoj 2653 middle(二分+主席树)
- bzoj2653 middle(主席树+二分)
- [主席树+二分] BZOJ2653: middle
- 【bzoj2653】【middle】【主席树+二分答案】
- BZOJ 2653 middle 二分+主席树
- [BZOJ2653]middle(二分+主席树)
- 【BZOJ2653】【主席树+二分】middle
- bzoj2653 Middle 二分&主席树