题目大意(:)给定一个序列,刚开始序列为空,每次向序列中插入一个数(X),同时维护并输出插入完后序列的中位数为多少。保证(0leq X < 2^{31}),且插入的数的个数(N<10000)。
分析(:)数据范围虽然只有(10000),显然我们可以每次插入完之后暴力(sort),然后输出序列中间的值即可。但这道题的数据范围明显可以增大到(1e5),直接会把暴力的做法卡死。
所以我们考虑正解(:)平衡树
平衡树维护中位数时,每次插入完一个数,若当前数的个数为偶数,则查询并输出排名为(n>>1)和(n>>1|1)的两个位置的数的平均数;若当前数的个数为奇数,则直接输出排名为(n>>1|1)的位置的数即可。
至于平衡树的话,有以下几种选择(:)
-
(Treap :) 代码又臭又长,不好写,不好调试,不予考虑
-
(Splay:) 曾经的(flag:) 学(LCT)前只写(FHQ Treap!!)
-
(FHQ Treap :) 代码简短,思路清晰,常数略大,好写好调试
具体还有一些细节在代码里会有说明。
上代码(:)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
const int maxn = 1e6 + 5;
int n, m, w, ch;
template<class T>
inline T read(T &x) {
x = 0, w = 1, ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') w = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - 48; ch = getchar();}
return x *= w;
} // 来份快读
struct Node {
int ls, rs, size;
int key, val;
}z[maxn];
int root, cnt;
int l, r, temp;
void update(int rt) {
z[rt].size = z[z[rt].ls].size + z[z[rt].rs].size + 1;
}
int new_node(int x) {
++cnt;
z[cnt].size = 1;
#ifdef Unix
z[cnt].key = rand();
#else
z[cnt].key = rand() << 15 + rand();
#endif // Unix
// Lunix 系统下rand()可以取到INT_MAX,windows系统下只能取到3万多,所以差别处理
z[cnt].val = x;
return cnt;
}
int merge(int x, int y) { // 合并操作
if (!x || !y) return x + y;
if (z[x].key < z[y].key) {
z[x].rs = merge(z[x].rs, y);
update(x);
return x;
}
else {
z[y].ls = merge(x, z[y].ls);
update(y);
return y;
}
}
void split(int rt, int x, int &l, int &r) { // 分离操作
if (!rt) l = r = 0;
else {
if (x < z[rt].val) {
r = rt;
split(z[rt].ls, x, l, z[rt].ls);
}
else {
l = rt;
split(z[rt].rs, x, z[rt].rs, r);
}
update(rt);
}
}
int rnk(int rt, int x) { //查询排名为x的数的位置
while(true) {
if (x <= z[z[rt].ls].size) {
rt = z[rt].ls;
}
else if (z[z[rt].ls].size + 1 == x) return rt;
else {
x -= z[z[rt].ls].size + 1;
rt = z[rt].rs;
}
}
}
int main() {
srand(time(NULL)); // 随机数……
while (scanf("%d", &temp) != EOF) {
split(root, temp, l, r);
root = merge(merge(l, new_node(temp)), r); // fhq treap 的 insert (基本操作)
if (cnt & 1) {
printf("%d
", z[rnk(root, (cnt >> 1) + 1)].val);
}
else {
int ans1 = z[rnk(root, cnt >> 1)].val, ans2 = z[rnk(root, (cnt >> 1) + 1)].val;
printf("%d
", (ans1 + ans2) >> 1);
}
}
return 0;
}
完结撒花d=====( ̄▽ ̄*)b