BZOJ 2653 middle
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=2653
题目大意:多组询问,求左右端点在规定范围内移动所能得到的最大中位数。
[分析]
求中位数这类题目比较少见[笔者见识少...],但是它的性质比较优美——从小到大排序排在中间的数字。
如果往常求一个无序数列的中位数,最好的复杂度就是n*logn[快排一遍的复杂度],[因为你要知道每个元素在序列中的大小]
但是我们这里是多组询问,而且元素不会修改,也就是每个元素的相对大小会在一开始预处理就搞定。
现在我们再来想:左右端点只是一个范围,怎么求出满足情况的最优区间呢?
根据时间的效率,肯定不能用枚举。
那么这个区间就一定有性质,什么性质呢?中位数最大。
我们要从中位数最大来找到这个区间。
也就是这个区间里比中位数大的元素和比中位数小的元素一样多。
可想而知:我们希望这个区间内的大的数越多,小的数越少越好,可是大小只是一个相对的概念,必须要和中位数比较才知道什么叫大,什么叫小。
谁是最大的中位数呢?求的就是这个,我们怎么知道...那我们只好二分了。
二分出这个中位数之后,我们要找这个最优区间就好办了:
假设比中位数小的数值记作-1,比中位数大的数值记作1。
最优区间一定满足:区间元素[指的是1,-1这些数]的和最大。
求最大和的这个过程可以用很多数据结构解决了,即求[a,b]的右端最大+(b,c)的和+[c,d]的左端最大。
可是我其实只需要这个值大于0,当前二分的值就是合法的了,我就会去追求一个更大的中位数,对吧。
也就是说,思考的过程是:
二分一个答案->找到最优的区间->区间如果满足->去追寻更好的答案。
其中最优区间是找寻答案的前提,但只有先暂时确定一个较好值才能找到符合这个的最优区间。[逻辑上有点成环]
最后因为对于每个二分出来的中位数值都希望有一个[-1,1]的序列专门分给它,这个靠什么呢?
想起之前的可持久化线段树就好办了:
树的节点意义是下标的位置范围,树的节点同时需要记录下这个节点代表区间的“右端最大”、“左端最大”、“求和”三种属性
最小的元素所有位置都标上1[因为所有元素都比它大嘛...],
然后从小到大的添加元素,先复制上一棵树,每次将树上上一个元素所在的位置标上-1,同时需要在过程中更新出右端最大、左端最大、求和三种属性。
因为上一棵树和这一棵树的唯一区别就是上一棵树在上一个元素的位置上标记为1,而这一棵树标记为-1,这样每次就是更新树上的一条链,变化不会很大,采用的就是可持久化线段树的思想了。
最后献上代码:
#include<cstdio>
#include<cstring>
#include<algorithm> using namespace std; inline int in(){
int x=;char ch=getchar();
while(ch>'' || ch<'') ch=getchar();
while(ch>='' && ch<='') x=x*+ch-'',ch=getchar();
return x;
} const int maxn=; int n,m,key,cnt,ans;
int a[maxn];
int id[maxn],rt[maxn]; struct Node{
int l,r,sz;
int lx,rx,sm;
}s[maxn*]; bool cmp(const int &x1,const int &x2){
return a[x1]<a[x2];
} void renew(int x){
s[x].sm=s[s[x].l].sm+s[s[x].r].sm;
s[x].lx=max(s[s[x].l].lx,s[s[x].l].sm+s[s[x].r].lx);
s[x].rx=max(s[s[x].r].rx,s[s[x].r].sm+s[s[x].l].rx);
} void build(int l,int r,int &rt){
if(l==r){
rt=++cnt,s[rt].sm=s[rt].lx=s[rt].rx=;
return ;
}
rt=++cnt;
int mid=(l+r)>>;
build(l,mid,s[rt].l);
build(mid+,r,s[rt].r);
renew(rt);
} void update(int last,int l,int r,int &rt,int val){
rt=++cnt;s[rt]=s[last];
if(l==r){
s[rt].lx=s[rt].rx=s[rt].sm=val;
return ;
}
int mid=(l+r)>>;
if(key<=mid) update(s[last].l,l,mid,s[rt].l,val);
else update(s[last].r,mid+,r,s[rt].r,val);
renew(rt);
} int get_all(int rt,int l,int r,int x,int y){
if(l==x && r==y) return s[rt].sm;
int mid=(l+r)>>;
if(y<=mid)
return get_all(s[rt].l,l,mid,x,y);
else if(x>mid)
return get_all(s[rt].r,mid+,r,x,y);
else
return get_all(s[rt].l,l,mid,x,mid)+get_all(s[rt].r,mid+,r,mid+,y);
} int get_lx(int rt,int l,int r,int x,int y){
if(l==x && r==y) return s[rt].lx;
int mid=(l+r)>>;
if(y<=mid)
return get_lx(s[rt].l,l,mid,x,y);
else if(x>mid)
return get_lx(s[rt].r,mid+,r,x,y);
else
return max(get_lx(s[rt].l,l,mid,x,mid),get_all(s[rt].l,l,mid,x,mid)+get_lx(s[rt].r,mid+,r,mid+,y));
} int get_rx(int rt,int l,int r,int x,int y){
if(l==x && r==y) return s[rt].rx;
int mid=(l+r)>>;
if(y<=mid)
return get_rx(s[rt].l,l,mid,x,y);
else if(x>mid)
return get_rx(s[rt].r,mid+,r,x,y);
else
return max(get_rx(s[rt].r,mid+,r,mid+,y),get_all(s[rt].r,mid+,r,mid+,y)+get_rx(s[rt].l,l,mid,x,mid));
} bool check(int k,int a,int b,int c,int d){
int sum=;
if(c>b+) sum+=get_all(rt[k],,n-,b+,c-);
sum+=get_rx(rt[k],,n-,a,b);
sum+=get_lx(rt[k],,n-,c,d);
return sum>=;
} int main(){
#ifndef ONLINE_JUDGE
freopen("2653.in","r",stdin);
freopen("2653.out","w",stdout);
#endif n=in();
for(int i=;i<n;i++)
a[i]=in(),id[i]=i;
sort(id,id+n,cmp);
build(,n-,rt[]);
for(int i=;i<n;i++)
key=id[i-],update(rt[i-],,n-,rt[i],-); int ord[]; m=in();
while(m--){
ord[]=in(),ord[]=in(),ord[]=in(),ord[]=in();
for(int i=;i<;i++)
ord[i]=(ord[i]+ans)%n;
sort(ord,ord+);
int l=,r=n,mid;
while(l+<r){
mid=(l+r)>>;
if(check(mid,ord[],ord[],ord[],ord[])) l=mid;
else r=mid;
}
ans=a[id[l]];
printf("%d\n",ans);
} return ;
}
BZOJ 2653 middle的更多相关文章
- [BZOJ 2653] middle(可持久化线段树+二分答案)
[BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...
- bzoj 2653: middle (主席树+二分)
2653: middle Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2522 Solved: 1434[Submit][Status][Disc ...
- BZOJ 2653: middle 主席树 二分
https://www.lydsy.com/JudgeOnline/problem.php?id=2653 因为是两个方向向外延伸所以不能对编号取前缀和(这里只有前缀和向后传递的性质,不是实际意义的和 ...
- BZOJ 2653 middle | 主席树
题目: http://www.lydsy.com/JudgeOnline/problem.php?id=2653 题解: 设答案为ans,把大于等于ans的记为1,小于的记为-1,这样可以知道当前an ...
- bzoj 2653 middle (可持久化线段树)
middle Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1981 Solved: 1097[Submit][Status][Discuss] D ...
- BZOJ 2653: middle [主席树 中位数]
传送门 题意: 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个 长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右 ...
- bzoj 2653 middle 二分答案 主席树判定
判断中位数是否可行需要将当前的解作为分界,大于其的置为1,小于为-1,然后b-c必选,ab,cd可不选,这个用线段树判定就好 但不能每次跑,所以套主席树,按权值排序,构建主席树,更新时将上一个节点改为 ...
- BZOJ 2653 middle 二分答案+可持久化线段树
题目大意:有一个序列,包含多次询问.询问区间左右端点在规定区间里移动所得到的最大中位数的值. 考虑对于每个询问,如何得到最优区间?枚举显然是超时的,只能考虑二分. 中位数的定义是在一个序列中,比中位数 ...
- bzoj 2653 middle(主席树)
题面:https://vjudge.net/problem/HYSBZ-2653 博客:https://blog.csdn.net/litble/article/details/78984846 这个 ...
随机推荐
- 关于Ajax跨域
本人因工作需求,编写了一个测试页面,在页面填写完信息之后去向一个站点请求数据,然后返回结果!一开始是直接用Ajax在脚本中去访问,没有大碍(因为目标地址是本机上的一个网站),但是当站点去外部的网站时, ...
- Knockout.Js官网学习(简介)
前言 最近一段时间在网上经常看到关于Knockout.js文章,于是自己就到官网看了下,不过是英文的,自己果断搞不来,借用google翻译了一下.然后刚刚发现在建立asp.net mvc4.0的应用程 ...
- 将List<T>转化成 DataTable--调整可空类型的转化错误
加载表结构并保持成XML string cmdText = @"select * from kb_lable_temp where 1=2"; using (SqlConnecti ...
- Linux命令学习---目录
一.文件相关命令 1.文件显示 1)tail,head,more,less,cat,nl
- 关于MySQL建表
规范一些常用字段. password:varchar name:varchar 时间存储全部存储时间戳,用bigint(20),拒绝使用 MySQL数据类型 mysql数据类型 含义 date 3字 ...
- mysql 格式化时间
SELECT phone,chang, msg, linkid, DATE_FORMAT(mo_time, '%Y%m%d%H%i%s') FROM mo http://www.w3school.co ...
- Json 调用 天气API 实例
百度了一下,找了点别人的方法改进了一下. 获取天气网址:http://www.weather.com.cn/html/weather/101210701.shtml这里是温州的,当然其他城市自己搜索一 ...
- Laravel 5 基础(五)- 环境与配置
.env 文件是配置文件,包括数据库配置信息,查看 config->database.php ,connections 里面包含了所有数据库的配置,可以在 default 中选择要使用的数据库. ...
- MySql中把一个表的数据插入到另一个表中的实现代码
web开发中,我们经常需要将一个表的数据插入到另外一个表,有时还需要指定导入字段,设置只需要导入目标表中不存在的记录,虽然这些都可以在程序中拆分成简单sql来实现,但是用一个sql的话,会节省大量代码 ...
- python匿名函数(lambda)
简单来说,编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数 当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方 ...