BZOJ2653:middle——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=2653
Description
Input
Output
Q行依次给出询问的答案。
Sample Input
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
Sample Output
271451044
271451044
969056313
——————————————————————————
debug真爽……一会再讲我神奇的debug经历。
(因为参照代码太多了所以就不一一贴了)
我们考虑如何求一个数比中位数大还是小。
方法很简单:将小于该数的数一律变成-1,大于等于的变为1,求和,如果和>=0即*可能为*这个数。
也就是说,我们可以用这个方法二分答案来求得中位数。
那么我们对于一组询问a,b,c,d,判断x与中位数的大小关系,就可以是求最大子序列和的过程了。
那么我们按照元素下标建线段树,并且存储每个区间的最大左/右连续和,,每个区间的和。
那么答案就是(ab最大右连续和)+(bc和)+(cd最大左连续和)。
但是我们不可能为每一组询问重新开一棵线段树,所以我们需要一种*预处理*所有可能的线段树的方法。
于是我们想到了主席树。
我们先对数列排序,这样假设我们中位数下标(以下都是排序后的新下标)为x,则显然0~x-1都是-1,而x~n-1都是1
那么我们的建树过程无非就是第一棵树全是1,而后的树对于前面的树的值都更新为-1就可以了。
(看着复杂,代码也复杂,debug1h一无所获,最后我精简代码发现我i和j搞反了……)
- #include<cstdio>
- #include<queue>
- #include<cctype>
- #include<cstring>
- #include<cmath>
- #include<vector>
- #include<algorithm>
- using namespace std;
- const int N=;
- inline int read(){
- int X=,w=;char ch=;
- while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
- while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
- return w?-X:X;
- }
- struct tree{
- int l,r,sum,lx,rx;
- }tr[N*];
- struct num{
- int v,p;
- }a[N];
- int rt[N],n,m,q,pool,p[];
- bool cmp(num f,num s){return f.v<s.v;}
- inline void update(int x){
- tr[x].sum=tr[tr[x].l].sum+tr[tr[x].r].sum;
- tr[x].lx=max(tr[tr[x].l].lx,tr[tr[x].l].sum+tr[tr[x].r].lx);
- tr[x].rx=max(tr[tr[x].r].rx,tr[tr[x].r].sum+tr[tr[x].l].rx);
- return;
- }
- inline void build(int &x,int l,int r){
- x=++pool;
- if(l==r){
- tr[x].sum=tr[x].lx=tr[x].rx=;
- return;
- }
- int mid=(l+r)>>;
- build(tr[x].l,l,mid);
- build(tr[x].r,mid+,r);
- update(x);
- return;
- }
- inline void insert(int y,int &x,int l,int r,int p,int v){
- tr[x=++pool]=tr[y];
- if(l==r){
- tr[x].sum=tr[x].lx=tr[x].rx=v;
- return;
- }
- int mid=(l+r)>>;
- if(p<=mid)insert(tr[y].l,tr[x].l,l,mid,p,v);
- else insert(tr[y].r,tr[x].r,mid+,r,p,v);
- update(x);
- return;
- }
- inline int query_all(int k,int l,int r,int l1,int r1){
- if(l==l1&&r==r1)return tr[k].sum;
- int mid=(l+r)>>;
- if(r1<=mid) return query_all(tr[k].l,l,mid,l1,r1);
- else if(l1>mid) return query_all(tr[k].r,mid+,r,l1,r1);
- else return query_all(tr[k].l,l,mid,l1,mid)+query_all(tr[k].r,mid+,r,mid+,r1);
- }
- inline int query_l(int k,int l,int r,int l1,int r1){
- if(l==l1&&r==r1)return tr[k].lx;
- int mid=(l+r)>>;
- if(r1<=mid) return query_l(tr[k].l,l,mid,l1,r1);
- else if(l1>mid) return query_l(tr[k].r,mid+,r,l1,r1);
- else return max(query_l(tr[k].l,l,mid,l1,mid),query_all(tr[k].l,l,mid,l1,mid)+query_l(tr[k].r,mid+,r,mid+,r1));
- }
- inline int query_r(int k,int l,int r,int l1,int r1){
- if(l==l1&&r==r1)return tr[k].rx;
- int mid=(l+r)>>;
- if(r1<=mid) return query_r(tr[k].l,l,mid,l1,r1);
- else if(l1>mid) return query_r(tr[k].r,mid+,r,l1,r1);
- else return max(query_r(tr[k].r,mid+,r,mid+,r1),query_all(tr[k].r,mid+,r,mid+,r1)+query_r(tr[k].l,l,mid,l1,mid));
- }
- bool pan(int k){
- int sum=;
- if(p[]+<p[])sum+=query_all(rt[k],,n-,p[]+,p[]-);
- sum+=query_r(rt[k],,n-,p[],p[]);
- sum+=query_l(rt[k],,n-,p[],p[]);
- return sum>=;
- }
- int erfen(){
- int l=,r=n-,ans;
- while(l<=r){
- int mid=(l+r)>>;
- if(pan(mid)){
- ans=a[mid].v;
- l=mid+;
- }else r=mid-;
- }
- return ans;
- }
- int main(){
- n=read();
- for(int i=;i<n;i++){
- a[i].v=read();
- a[i].p=i;
- }
- sort(a,a+n,cmp);
- build(rt[],,n-);
- for(int i=;i<n;i++)insert(rt[i-],rt[i],,n-,a[i-].p,-);
- q=read();
- int pre=;
- for(int i=;i<=q;i++){
- for(int j=;j<;j++)p[j]=(read()+pre)%n;
- sort(p,p+);
- printf("%d\n",pre=erfen());
- }
- return ;
- }
BZOJ2653:middle——题解的更多相关文章
- BZOJ2653 middle 【主席树】【二分】*
BZOJ2653 middle Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个长度为n的序列s.回答Q个这样 ...
- 题解【bzoj2653 middle】
Description 给你一个序列,每次询问给出四个数 \(a,b,c,d\),求所有区间 \([l,r]\) 满足 \(l \in [a,b], r \in [c,d]\) 的中位数的最大值.强制 ...
- bzoj2653: middle
首先,对于每个询问,我们二分答案 然后对于序列中大于等于中位数的数,我们把它们置为1,小于中位数的数,置为-1 那么如果一个区间和大于等于0,那么就资磁,否则就不滋磁 这个区间和呢,我们可以用主席树维 ...
- BZOJ2653 middle(二分答案+主席树)
与中位数有关的题二分答案是很常用的trick.二分答案之后,将所有大于它的看成1小于它的看成-1,那么只需要判断是否存在满足要求的一段和不小于0. 由于每个位置是1还是-1并不固定,似乎不是很好算.考 ...
- [BZOJ2653]middle 主席树+二分
2653: middle Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2042 Solved: 1123[Submit][Status][Disc ...
- BZOJ2653 middle 【二分 + 主席树】
题目 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个 长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c ...
- [bzoj2653][middle] (二分 + 主席树)
Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b ...
- Luogu2839 [国家集训队]middle 题解
题目很好,考察对主席树的深入理解与灵活运用. 首先看看一般解决中位数的思路,我们二分一个 \(mid\),将区间中 \(\ge mid\) 的数置为 \(1\),小于的置为 \(-1\),然后求区间和 ...
- PKUSC2018训练日程(4.18~5.30)
(总计:共66题) 4.18~4.25:19题 4.26~5.2:17题 5.3~5.9: 6题 5.10~5.16: 6题 5.17~5.23: 9题 5.24~5.30: 9题 4.18 [BZO ...
随机推荐
- 三分钟小课堂-----------------docker(三)增删改查命令
主要为docker容器的增删改查命令 1 创建容器: docker run -it --name 别名 image_name /bin/bash --name 别名 -d 后台 -t ...
- Objective-C 构造方法 分类 类的深入研究
构造方法 1.对象创建的原理 new的拆分两部曲 Person *p = [Person alloc]; 分配内存(+alloc) Person *p = [p init]; 初始化(-init) 合 ...
- VMware SDK使用指南
刚开始用VMware官方推荐的SDK,真的是又臭又长,代码结构不清晰,易读性差.后来VMware的同学给推荐了一款开源的SDK,一上手感觉工作效率提高了100倍!推荐大家使用~. 该SDK对VMwar ...
- TW实习日记:第28天
同前两天一样,等接口,开发,调试接口.重复地做着低级代码得搬运工作,确实挺没意思的.怪不得有些人一直说写低级代码很无聊,没有创造性和成就感.31号准备溜了,还是好好复习准备秋招吧. 挖坑清单: Vue ...
- python数据分析基础——pandas Tutorial
参考pandas官方文档: http://pandas.pydata.org/pandas-docs/stable/10min.html#min 1.pandas中的数据类型 Series 带有索引标 ...
- Visual Stdio Code编辑Mark Down
Visual Studio Code可以一边写Markdown一边预览了,而且不需要任何插件. 方法如下: 新建一个文件,以 .md 为后缀: Visual Studio Code 原生就支持高亮Ma ...
- 改maven下创建的动态网站依赖的jre版本
问题描述 通过maven创建一个动态网站后,eclipse会提示一个提醒 Build path specifies execution environment J2SE-1.5. There are ...
- ElasticSearch 2.0以后的改动导致旧的资料和书籍需要订正的部分
id原先是可以通过path指定字段的 "thread": { "_id" : { "path" : "thread_id" ...
- java一些面试题
java虚拟机 什么时候会触发full gc System.gc()方法的调用 老年代空间不足 永生区空间不足(JVM规范中运行时数据区域中的方法区,在HotSpot虚拟机中又被习惯称为永生代或者永生 ...
- spring boot 中文乱码问题
在刚接触spring boot 2.0的时候,遇到了一些中文乱码的问题,网上找了一些解决方法. 这里自己做个汇总. 在application.properties文件中添加: spring.http. ...