先上一波链接 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/线段树的更多相关文章

  1. 【BZOJ】1012: [JSOI2008]最大数maxnumber /【洛谷】1198(线段树)

    Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插 ...

  2. 洛谷题解P4314CPU监控--线段树

    题目链接 https://www.luogu.org/problemnew/show/P4314 https://www.lydsy.com/JudgeOnline/problem.php?id=30 ...

  3. 洛谷P3372/poj3468(线段树lazy_tag)(询问区间和,支持区间修改)

    洛谷P3372 //线段树 询问区间和,支持区间修改 #include <cstdio> using namespace std; struct treetype { int l,r; l ...

  4. 洛谷P4065 [JXOI2017]颜色(线段树)

    题意 题目链接 Sol 线段树板子题都做不出来,真是越来越菜了.. 根据题目描述,一个合法区间等价于在区间内的颜色没有在区间外出现过. 所以我们可以对于每个右端点,统计最长的左端点在哪里,刚开始以为这 ...

  5. 洛谷P5111 zhtobu3232的线段树

    题意:给定线段树,上面若干个节点坏了,求能表示出多少区间. 区间能被表示出当且仅当拆出来的log个节点都是好的. 解:每个区间在最浅的节点处计算答案. 对于每个节点维护从左边过来能有多少区间,从右边过 ...

  6. 洛谷P3960 列队 NOIp2017 线段树/树状数组/splay

    正解:动态开点线段树 解题报告: 传送门! 因为最近学主席树的时候顺便get到了动态开点线段树?刚好想起来很久很久以前就想做结果一直麻油做的这题,,,所以就做下好了QAQ 然后说下,这题有很多种方法, ...

  7. 题解——洛谷P2781 传教(线段树)

    可以说是数据结构学傻了的典型案例了 昨天跳到这题上 然后思考了一下 噫!好!线段树裸题 然后打完板子,发现\(  n \le 10^9 \) 显然线段树直接做不太行 然后这题又只有普及的难度 然后我就 ...

  8. 洛谷P4198 楼房重建(线段树)

    题意 题目链接 Sol 别问我为什么发两遍 就是为了骗访问量 这个题的线段树做法,,妙的很 首先一个显然的结论:位置\(i\)能被看到当且仅当\(\frac{H_k}{k} < \frac{H_ ...

  9. 2018.08.16 洛谷P1471 方差(线段树)

    传送门 线段树基本操作. 把那个方差的式子拆开可以发现只用维护一个区间平方和和区间和就可以完成所有操作. 同样区间修改也可以简单的操作. 代码: #include<bits/stdc++.h&g ...

随机推荐

  1. javascript事件触发器fireEvent和dispatchEvent

    javascript事件触发器fireEvent和dispatchEvent   事件触发器就是用来触发某个元素下的某个事件,IE下fireEvent方法,高级浏览器(chrome,firefox等) ...

  2. java httpclient basic授权

    import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpS ...

  3. Linux安装postgresql及基础操作

    安装环境说明 系统环境说明 [root@slave1 ~]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) [root@sl ...

  4. 实现 unity MonoBehaviour API5.4 的消息

      顺序(第一次执行.忽略循环) 方法 说明 Editor 1 void Reset() 重置为默认值 ------------------------------------------------ ...

  5. 比较两个Sql数据库是否相同

    1.打开VS20122.SQL→架构比较→新建架构比较3.在源和目标上分别填上两个待比较的数据库的信息4.点击比较,不一会儿,系统就会列出两个数据库的差异了.

  6. 07.SUSE Linux 系统本地yum源配置

    SUSE Linux 系统 1.新建本地源存储目录root@suse:mkdir /mnt/SUSE_LOCAL_SOURCE 2.创建zypper本地源root@suse:zypper ar fil ...

  7. JAVA 关于File的使用

    File中常用方法 创建 createNewFile() 在指定位置创建一个空文件,成功就返回true,如果已存在就不创建然后返回false mkdir() 在指定位置创建目录,这只会创建最后一级目录 ...

  8. 前端每日实战:32# 视频演示如何用纯 CSS 创作六边形按钮特效

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/xjoOeM 可交互视频教程 此视频 ...

  9. 前端面试题(4)JavaScript

    前端面试题JavaScript(一) JavaScript的组成 JavaScript 由以下三部分组成: ECMAScript(核心):JavaScript 语言基础 DOM(文档对象模型):规定了 ...

  10. Linux命令行工具之vmstat命令

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11484608.html vmstat是一款指定采样周期和次数的功能性监测工具,可以使用它监控进程上下文 ...