UVA10107 【What is the Median?】
题目大意\(:\)给定一个序列,刚开始序列为空,每次向序列中插入一个数\(X\),同时维护并输出插入完后序列的中位数为多少。保证\(0\leq 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\n", 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\n", (ans1 + ans2) >> 1);
}
}
return 0;
}
完结撒花d=====( ̄▽ ̄*)b