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

posted @ 2019-10-25 14:53  Hydrogen_Helium  阅读(89)  评论(0编辑  收藏  举报