P3871 [TJOI2010]中位数

题目描述

给定一个由N个元素组成的整数序列,现在有两种操作:

1 add a

在该序列的最后添加一个整数a,组成长度为N + 1的整数序列

2 mid 输出当前序列的中位数

中位数是指将一个序列按照从小到大排序后处在中间位置的数。(若序列长度为偶数,则指处在中间位置的两个数中较小的那个)

例1:1 2 13 14 15 16 中位数为13

例2:1 3 5 7 10 11 17 中位数为7

例3:1 1 1 2 3 中位数为1

输入输出格式

输入格式:

第一行为初始序列长度N。第二行为N个整数,表示整数序列,数字之间用空格分隔。第三行为操作数M,即要进行M次操作。下面为M行,每行输入格式如题意所述。

输出格式:

对于每个mid操作输出中位数的值

输入输出样例

输入样例#1:

6
1 2 13 14 15 16
5
add 5
add 3
mid
add 20
mid

输出样例#1:

5
13

说明

对于30%的数据,1 ≤ N ≤ 10,000,0 ≤ M ≤ 1,000

对于100%的数据,1 ≤ N ≤ 100,000,0 ≤ M ≤ 10,000

序列中整数的绝对值不超过1,000,000,000,序列中的数可能有重复

Solution:

本题有很多做法。

1、先说一种简单点的,使用“对顶堆”的在线算法。为了动态维护中位数,我们可以建立两个二叉堆,一个小根堆一个大根堆,在读入序列时,注意:将从小到大排名为1~n/2的整数放在大根堆中,将从小到大排名为n/2+1~n的整数放在小根堆中。

每次新读入一个数x后,若x比大根堆顶小,则放入大根堆,否则放入小根堆。在查询时,若某个大根堆元素个数过多(>n/2),则将多余的元素放入小根堆,那么若此时n为奇数则中位数为小根堆堆顶,否则就是大根堆堆顶,直接输出就OK了。

代码:

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 #define ll long long
 4 #define debug printf("%d%s\n",__LINE__,__FUNCTION__)
 5 using namespace std;
 6 const int N=100005;
 7 il int gi()
 8 {
 9     int a=0;char x=getchar();bool f=0;
10     while((x<‘0‘||x>‘9‘)&&x!=‘-‘)x=getchar();
11     if(x==‘-‘)x=getchar(),f=1;
12     while(x>=‘0‘&&x<=‘9‘)a=a*10+x-48,x=getchar();
13     return f?-a:a;
14 }
15 priority_queue<int,vector<int>,greater<int> >qmin;
16 priority_queue<int>qmax;
17 int n,x,mid,a[N],m,cn1,cn2;
18 int main()
19 {
20     n=gi();m=n;
21     for(int i=1;i<=n;i++)a[i]=gi();
22     sort(a+1,a+n+1);
23     for(int i=1;i<=n/2;i++)qmax.push(a[i]),cn1++;
24     for(int i=n/2+1;i<=n;i++)qmin.push(a[i]),cn2++;
25     n=gi();char s[10];
26     while(n--){
27         scanf("%s",s);
28         if(s[0]==‘a‘){
29             scanf("%d",&x);
30             if(x<qmax.top())qmax.push(x),cn1++;
31             else qmin.push(x),cn2++;
32             m++;
33         }
34         else {
35             while(cn1<m/2){
36                 x=qmin.top();qmin.pop();qmax.push(x);cn1++;cn2--;
37             }
38             while(cn1>m/2){
39                 x=qmax.top();qmax.pop();qmin.push(x);cn2++;cn1--;
40             }
41             if(m&1)printf("%d\n",qmin.top());
42             else printf("%d\n",qmax.top());
43         }
44     }
45     return 0;
46 }

2、“链表+hash”离线做法。

3、还有一种无脑的平衡树在线做法(自我感觉大才小用了)。

原文地址:https://www.cnblogs.com/five20/p/8509376.html

时间: 2024-10-17 07:10:02

P3871 [TJOI2010]中位数的相关文章

luoguP3871 [TJOI2010]中位数

题目链接 luoguP3871 [TJOI2010]中位数 题解 平衡树 代码 #include<vector> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long inline int read() { int x = 0,f = 1;char c = getchar(); while(c < '0'||c > '9'){if(c == '-')

[TJOI2010]中位数

题目描述 给定一个由N个元素组成的整数序列,现在有两种操作: 1 add a 在该序列的最后添加一个整数a,组成长度为N + 1的整数序列 2 mid 输出当前序列的中位数 中位数是指将一个序列按照从小到大排序后处在中间位置的数.(若序列长度为偶数,则指处在中间位置的两个数中较小的那个) 例1:1 2 13 14 15 16 中位数为13 例2:1 3 5 7 10 11 17 中位数为7 例3:1 1 1 2 3 中位数为1 输入输出格式 输入格式: 第一行为初始序列长度N.第二行为N个整数,

题解-BOI 2004 Sequence

Problem bzoj & Luogu 题目大意: 给定序列\(\{a_i\}\),求一个严格递增序列\(\{b_i\}\),使得\(\sum \bigl |a_i-b_i\bigr|\)最小 Thought 正序:直接对应 逆序:取中位数(证明:"医院设置") 最优解一定是分段 每一段台阶式上升 每一段选取中位数 沙漏型左偏树 合并区间 选取中位数 upd:貌似不需要沙漏型? Solution 前置技能:小学奥数.可并堆 和上面类似,先不考虑严格上升,即先考虑非严格上升 序

平衡树24题(更新中…)

平衡树24题(更新中-) 前言: 我写的平衡树题里不是用Treap解决的,就是用Fhq-Treap写的,还有极少数是用Splay写的. 说说这几个树的区别与优劣: Treap是编码相对来说最容易的,但是由于它的结构不能改变,以致许多题目不能实现,区间操作也不行.一般来说,Treap可以打裸题,或者作为其它算法的辅助算法. Fhq-Treap一般来说Splay能做的它都可以.编码比Splay容易,容易理解.功能强大.唯一不足的是在LCT没有Splay优秀. Splay很灵活,一般所有情况都可以处理

【TJOI2010】中位数

Description 设计一种数据结构,支持元素的插入,查询当前元素的中位数 Solution 为了练习Splay,我决定用牛刀杀鸡,用Splay解决对顶堆的问题. 然后这就是一道Splay的模板题(简化简化再简化) Code 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int INF = 2147483647; 4 struct Splay { 5 int sum, cnt, val; 6 int fa, ch[2];

2-13. 两个有序序列的中位数(25)(ZJUPAT )

题目链接:http://pat.zju.edu.cn/contests/ds/2-13 已知有两个等长的非降序序列S1, S2, 设计函数求S1与S2并集的中位数.有序序列A0, A1-AN-1的中位数指A(N-1)/2的值,即第[(N+1)/2]个数(A0为第1个数). 输入格式说明: 输入分3行.第1行给出序列的公共长度N(0<N<=100000),随后每行输入一个序列的信息,即N个非降序排列的整数.数字用空格间隔. 输出格式说明: 在一行中输出两个输入序列的并集序列的中位数. 样例输入与

滑动窗口的中位数

2017年8月7日 19:46:26 难度:困难 描述:给定一个包含 n 个整数的数组,和一个大小为 k 的滑动窗口,从左到右在数组中滑动这个窗口,找到数组中每个窗口内的中位数.(如果数组个数是偶数,则在该窗口排序数字后,返回第 N/2 个数字.) 样例: 对于数组 [1,2,7,8,5], 滑动大小 k = 3 的窗口时,返回 [2,7,7] 最初,窗口的数组是这样的: [ | 1,2,7 | ,8,5] , 返回中位数 2; 接着,窗口继续向前滑动一次. [1, | 2,7,8 | ,5],

(LCA+树上主席树)FZU 2237 - 中位数

题意: 多次查询一个树链上的中位数(其实就是求K大). 分析: 感觉莫队可做,只是不会树上莫队.. 而且这里是边权,处理起来貌似有点小麻烦.. 后来发现其实貌似是一个很老的题,,kuangbin模板书上有类似的题. 树链上的第K大数,这是一道可以用主席树解的题,复杂度才nlogn. 这里也是这样先求从根到每个点的线段树,以为树存在父子关系,所有可以从让下层继承上层的线段树,非常符合主席树的可持久化思想. 然后在查询第K大的时候,去掉重复部分,就可以查了. 太强了,,, 代码: 1 #includ

leetcode链表--13、median-of-two-sorted-arrays(两个排序数组的中位数,时间复杂度)

题目描述 There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)). 题目解析:本题关键之处在于时间复杂度要求为O(log(m+n)),本题如果采用合并并排序两数组的方式,时间复杂度为O((m+n)*log(n+m))但是在牛客网上