洛谷P1168 中位数——set/线段树
先上一波链接 https://www.luogu.com.cn/problem/P1168
这道题我们有两种写法
第一种呢是线段树,我们首先需要将原本的数据离散化,线段树维护的信息就是区间内有多少个数,
每次加入两个数(也就是单点修改),查询的时候就是查找中位数((x+1)/2 )所在的位置
每次走到一个点 判断左子树中数字的个数(y)是不是就大于等于当前所找的数k 如果是 则往左子树继续走
如果左子树的数字个数(y)小于当前所找的数k,那么就将k减去y,再往右子树走,这样一直走下去就可以找到中位数所在的位置
然后再将其位置所对应的离散化前对应的点输出来就可以了 这样的复杂度是O(nlogn)的
贴一手代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int M=1e6+;
int read(){
int ans=,f=,c=getchar();
while(c<''||c>''){if(c=='-') f=-; c=getchar();}
while(c>=''&&c<=''){ans=ans*+(c-''); c=getchar();}
return ans*f;
}
struct qwq{int w,id;}s[M];
int n,xs[M],xp,fr[M];
struct node{int l,r,sum;}e[M];
void build(int x,int l,int r){
e[x].l=l; e[x].r=r;
if(l==r) return ;
int mid=(l+r)>>;
build(x<<,l,mid);
build(x<<^,mid+,r);
}
void up(int x){e[x].sum=e[x<<].sum+e[x<<^].sum;}
void ins(int x,int k){
if(e[x].l==e[x].r){
e[x].sum++;
return ;
}
int mid=(e[x].l+e[x].r)>>;
if(k<=mid) ins(x<<,k);
else ins(x<<^,k);
up(x);
}
int find(int x,int S){
if(e[x].l==e[x].r) return e[x].l;
if(e[x<<].sum>=S) return find(x<<,S);
return find(x<<^,S-e[x<<].sum);
}
int cnt=;
int main(){
n=read();
for(int i=;i<=n;i++){
s[i].w=read();
xs[++xp]=s[i].w;
}
sort(xs+,xs++xp);
for(int i=;i<=n;i++){
int now=lower_bound(xs+,xs+xp+,s[i].w)-xs;
s[i].id=now; fr[now]=s[i].w;
}
// for(int i=1;i<=n;i++) printf("%d ",s[i].id); puts("");
// for(int i=1;i<=n;i++) printf("%d ",fr[i]); puts("");
build(,,n);
ins(,s[].id);
for(int i=;i<=n;i+=){
int ans=find(,(i+)/);
printf("%d\n",fr[ans]);
ins(,s[++cnt].id);
ins(,s[++cnt].id);
}
return ;
}
另一种做法就是用multiset维护,我们将迭代器It 始终指向中位数,每次插入两个数
如果两个数都比他大,就将It++,因为此时中位数在当前 It 所在位置的后一位了
同理如果两个数都比他小,就将 It--, 如果一大一小,那么中位数位置不变,这样就圆满解决了问题
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<set>
using namespace std;
const int M=1e6+;
int read(){
int ans=,f=,c=getchar();
while(c<''||c>''){if(c=='-') f=-; c=getchar();}
while(c>=''&&c<=''){ans=ans*+(c-''); c=getchar();}
return ans*f;
}
int n,s[M],ans[M];
multiset<int>S;
multiset<int>::iterator It;
int main(){
//freopen("1.in","r",stdin);
n=read(); for(int i=;i<=n;i++) s[i]=read();
S.insert(s[]);
It=S.lower_bound(s[]);
int cnt=;
for(int i=;i<=(n+)/;i++){
ans[i]=*It;
S.insert(s[++cnt]);
S.insert(s[++cnt]);
if(s[cnt]>=*It&&s[cnt-]>=*It) ++It;
else if(s[cnt]<*It&&s[cnt-]<*It) --It;
printf("%d\n",ans[i]);
}
return ;
}
洛谷P1168 中位数——set/线段树的更多相关文章
- 【BZOJ】1012: [JSOI2008]最大数maxnumber /【洛谷】1198(线段树)
Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插 ...
- 洛谷题解P4314CPU监控--线段树
题目链接 https://www.luogu.org/problemnew/show/P4314 https://www.lydsy.com/JudgeOnline/problem.php?id=30 ...
- 洛谷P3372/poj3468(线段树lazy_tag)(询问区间和,支持区间修改)
洛谷P3372 //线段树 询问区间和,支持区间修改 #include <cstdio> using namespace std; struct treetype { int l,r; l ...
- 洛谷P4065 [JXOI2017]颜色(线段树)
题意 题目链接 Sol 线段树板子题都做不出来,真是越来越菜了.. 根据题目描述,一个合法区间等价于在区间内的颜色没有在区间外出现过. 所以我们可以对于每个右端点,统计最长的左端点在哪里,刚开始以为这 ...
- 洛谷P5111 zhtobu3232的线段树
题意:给定线段树,上面若干个节点坏了,求能表示出多少区间. 区间能被表示出当且仅当拆出来的log个节点都是好的. 解:每个区间在最浅的节点处计算答案. 对于每个节点维护从左边过来能有多少区间,从右边过 ...
- 洛谷P3960 列队 NOIp2017 线段树/树状数组/splay
正解:动态开点线段树 解题报告: 传送门! 因为最近学主席树的时候顺便get到了动态开点线段树?刚好想起来很久很久以前就想做结果一直麻油做的这题,,,所以就做下好了QAQ 然后说下,这题有很多种方法, ...
- 题解——洛谷P2781 传教(线段树)
可以说是数据结构学傻了的典型案例了 昨天跳到这题上 然后思考了一下 噫!好!线段树裸题 然后打完板子,发现\( n \le 10^9 \) 显然线段树直接做不太行 然后这题又只有普及的难度 然后我就 ...
- 洛谷P4198 楼房重建(线段树)
题意 题目链接 Sol 别问我为什么发两遍 就是为了骗访问量 这个题的线段树做法,,妙的很 首先一个显然的结论:位置\(i\)能被看到当且仅当\(\frac{H_k}{k} < \frac{H_ ...
- 2018.08.16 洛谷P1471 方差(线段树)
传送门 线段树基本操作. 把那个方差的式子拆开可以发现只用维护一个区间平方和和区间和就可以完成所有操作. 同样区间修改也可以简单的操作. 代码: #include<bits/stdc++.h&g ...
随机推荐
- Elasticsearch7.X 入门学习第八课笔记-----索引模板和动态模板
原文:Elasticsearch7.X 入门学习第八课笔记-----索引模板和动态模板 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接: ...
- 学Python的第七天
今天学习DBA有点乏,所以Python学的不是很多熬!!! 但是不管多苦多累Python不会放弃!! 虽然我是运维! #!/usr/bin/env python3 # -*- coding:utf-8 ...
- 解决SVN异常 cleanup failed
winndows上偶尔使用SVN的时候就会整出一些有的没的问题,比如"cleanup failed to process the following paths previous opera ...
- 21eval 函数
eval() 函数十分强大 ---- 将字符串 当成 有效的表达式 来求职 并 返回计算结果 # 基本的数学计算 # 字符串重复 print(eval("'*' * 5")) # ...
- OGG replicat复制进程的拆分
参考资料: 1.https://blog.csdn.net/datingting1/article/details/79583690
- AOP 和 IOC
IOC : 控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度.其中最常见的方式叫做依赖注入(Dependency ...
- Proto3语法翻译
本文主要对proto3语法翻译.参考网址:https://developers.google.com/protocol-buffers/docs/proto3 defining a message t ...
- bio编程示例
直接干代码,用BIO写一个Server端,然后使用telnet模拟客户端发送数据 import java.io.IOException; import java.io.InputStream; imp ...
- OC+RAC(六) 核心方法bind
-(void)_test6{ RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> ...
- ng mvc + @Valid + @RequestBody 接收json同时校验javaBean的数据有效性
@Valid @RequestBody CustomerDto customerBean @RequestMapping(value="/customerDataSync.do", ...