BZOJ 2653 middle 二分+主席树
来源:互联网 发布:fastdfs java 编辑:程序博客网 时间:2024/06/06 05:09
题意:
给定一个序列,多次询问左端点在[a,b],右端点在[c,d]的区间的中位数的最大值。
解析:
乍一看题,这什么玩意。
冷静冷静。
寻求中位数最大值?
上二分可不可以?
有没有单调性?
。。。。
我们发现,居然tmd有单调性?
我也是醉了
我们可以二分出来当前某个中位数。
然后我们把序列里所有的比它小的数看成-1,所有的比它大的数看成1。
然后我们只需要找左端点在[a,b],右端点在[c,d]是否存在一个区间使得该区间的和大于等于0
如果有的话,那么显然答案是可以再递增的,反之就需要减小答案。
然后我们就可以采取这种方式来二分中位数了。
但是值得注意的是,我们不能每一次对序列中的所有元素重新赋值,那样的话根本遭不住。
这时候可持久化数据结构的优势就体现出来了。
我们可以用主席树来解决这个问题。
具体方案就是我们把序列中的元素排序,从小到大加入。
初始把每个元素的值看作是1
然后每一次加入就相当于把上一个的值变成-1.(相等也可以改上一个不会影响答案)
这样我们每一次加入都是在原来的历史版本上重新搞一个新版本,主席树即可搞定。
至于二分部分。
左端点在[a,b],右端点在[c,d]中的某一段最大和区间。
显然(b,c)是必须取的。
于是就是rmax([a,b])+sum((b,c))+lmax([c,d])。
线段树里维护一个从左起的最大连续和以及从右起的最大连续和以及整段和即可。
注意上方()与[]的区别。
代码:
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 20010#define Q 25010#define M 401000#define INF 0x3f3f3f3fusing namespace std;int n,NO,q;int root[N];int size; struct node{ int lson,rson,sum,lmax,rmax;}seg[M];struct element{ int val,no; friend istream& operator >> (istream &_,element &a) {scanf("%d",&a.val),a.no=++NO;return _;}}a[N];int cmp(element a,element b){ return a.val<b.val;}void pushup(int rt){ int l=seg[rt].lson,r=seg[rt].rson; seg[rt].sum=seg[l].sum+seg[r].sum; seg[rt].lmax=max(seg[l].lmax,seg[l].sum+seg[r].lmax); seg[rt].rmax=max(seg[r].rmax,seg[r].sum+seg[l].rmax);}void build(int &rt,int l,int r){ if(!rt) rt=++size; if(l==r) { seg[rt].lmax=seg[rt].rmax=seg[rt].sum=1; return; } int mid=(l+r)>>1; build(seg[rt].lson,l,mid); build(seg[rt].rson,mid+1,r); pushup(rt);}void update(int y,int &x,int l,int r,int v,int val){ x=++size; seg[x]=seg[y]; if(l==r) { seg[x].lmax=seg[x].rmax=seg[x].sum=val; return; } int mid=(l+r)>>1; if(v<=mid)update(seg[y].lson,seg[x].lson,l,mid,v,val); else update(seg[y].rson,seg[x].rson,mid+1,r,v,val); pushup(x);}int query_sum(int rt,int L,int R,int l,int r){ if(L>R)return 0; int ret=0; if(L<=l&&r<=R) { return seg[rt].sum; } int mid=(l+r)>>1; if(L<=mid)ret+=query_sum(seg[rt].lson,L,R,l,mid); if(R>mid)ret+=query_sum(seg[rt].rson,L,R,mid+1,r); return ret;}int query_rmax(int rt,int L,int R,int l,int r){ if(L>R)return 0; int ret=-INF; if(L<=l&&r<=R) { return seg[rt].rmax; } int mid=(l+r)>>1; if(R<=mid)ret=max(ret,query_rmax(seg[rt].lson,L,R,l,mid)); else if(L>mid)ret=max(ret,query_rmax(seg[rt].rson,L,R,mid+1,r)); else { ret=max(ret,query_rmax(seg[rt].lson,L,mid,l,mid)+query_sum(seg[rt].rson,mid+1,R,mid+1,r)); ret=max(ret,query_rmax(seg[rt].rson,mid+1,R,mid+1,r)); } return ret;}int query_lmax(int rt,int L,int R,int l,int r){ if(L>R)return 0; int ret=-INF; if(L<=l&&r<=R) { return seg[rt].lmax; } int mid=(l+r)>>1; if(R<=mid)ret=max(ret,query_lmax(seg[rt].lson,L,R,l,mid)); else if(L>mid)ret=max(ret,query_lmax(seg[rt].rson,L,R,mid+1,r)); else { ret=max(ret,query_sum(seg[rt].lson,L,mid,l,mid)+query_lmax(seg[rt].rson,mid+1,R,mid+1,r)); ret=max(ret,query_lmax(seg[rt].lson,L,mid,l,mid)); } return ret;}int query[5];bool check(int x){ return query_rmax(root[x],query[1],query[2],1,n)+query_sum(root[x],query[2]+1,query[3]-1,1,n)+query_lmax(root[x],query[3],query[4],1,n)>=0;}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)cin>>a[i]; sort(a+1,a+n+1,cmp); build(root[1],1,n); for(int i=2;i<=n;i++) update(root[i-1],root[i],1,n,a[i-1].no,-1); int ans=0; scanf("%d",&q); for(int i=1;i<=q;i++) { scanf("%d%d%d%d",&query[1],&query[2],&query[3],&query[4]); for(int i=1;i<=4;i++)query[i]=(query[i]+ans)%n+1; sort(query+1,query+5); int tmp=0,l=1,r=n; while(l<=r) { int mid=(l+r)>>1; if(check(mid))tmp=mid,l=mid+1; else r=mid-1; } ans=a[tmp].val; printf("%d\n",ans); }}
0 0
- Bzoj 2653 middle(二分+主席树)
- BZOJ 2653 middle 二分+主席树
- [主席树 二分答案] BZOJ 2653 middle
- bzoj 2653: middle (二分+主席树)
- BZOJ 2653: middle 主席树+二分
- bzoj 2653 middle 二分答案 主席树判定
- 【主席树】 BZOJ 2653 middle
- 【主席树】BZOJ 2653 middle
- BZOJ 2653: middle|主席树
- HYSBZ 2653middle(二分+主席树)
- bzoj2653 Middle 二分&主席树
- [主席树+二分] BZOJ2653: middle
- bzoj 2653 二分+主席树
- [BZOJ]2653: middle 线段树合并+二分
- 【BZOJ 2653】middle 主席树好题推荐
- 【bzoj2653】【middle】【主席树+二分答案】
- [BZOJ2653]middle(二分+主席树)
- [BZOJ2653]middle(主席树+二分)
- C++通过jsoncpp类库读写JSON文件
- pread,pwrite,read,write区别
- DoTween 二:< 常用方法 —— 实现颜色渐变>
- 官网Maven简介
- 妙味js视频学习之旅(二)
- BZOJ 2653 middle 二分+主席树
- Install cuda7.5 in ubuntu14.04
- 数组旋转 返回将一维数组向右旋转k个位置的结果。比如,一维数组{1,2,3,4,5},k=2时,返回结果{4,5,1,2,3}。要求常数级空间复杂度,允许修改原有数组
- 初学机器学习的四种方式
- Java内部类、本地类、匿名类、文件类解读
- Linux系统安装Python
- Java IO 之 OutputStream源码
- bzoj1782: [Usaco2010 Feb]slowdown 慢慢游
- 默认拷贝构造函数究竟是什么