BZOJ 3196: Tyvj 1730 二逼平衡树

我了个大cao,总算调完了

emm,感觉线段树套treap还是非常好写的

我又双叒叕在空间计算上栽坑了QAQ

如果加垃圾回收,那么空间就是 50000 ( l o g 2 65536 + 1 ) ,但如果不加垃圾回收,我们假设所有的操作都是删除,那么最多新开 50000 ( l o g 2 65536 + 1 ) 个节点,所以空间应为 2 50000 ( l o g 2 65536 + 1 ) 的。

查询排名为 k 的数需要二分答案 m i d ,我一开始非常愚蠢地每次查询一遍 m i d n u m 然后判断是否满足 r a n k + 1 k r a n k + n u m ,其中 r a n k 表示比 m i d 小的数的个数,显然这么做的常数是非常大的……有一个聪明的做法,就是一旦 r a n k < k 就让 l = m i d + 1 , a n s = m i d ,否则 r = m i d 1 ,最后返回 a n s ,至于为什么很容易想懂。

#include <cstdio>
#include <cstdlib>

const int N = 50005, M = 1700005, INF = 0x7fffffff;

int cnt, siz[M], ch[M][2], val[M], num[M], rnd[M], a[N], root[N<<2], n;

int read() {
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}
int max(int x, int y) {
    if (x >= y) return x; return y;
}
int min(int x, int y) {
    if (x <= y) return x; return y;
}
void newNode(int &cur, int x) {
    cur = ++cnt;
    siz[cur] = num[cur] = 1;
    val[cur] = x, rnd[cur] = rand();
}
int cmp(int cur, int x) {
    cnt;
    if (val[cur] == x) return -1;
    return x < val[cur] ? 0 : 1;
}
void maintain(int cur) {
    siz[cur] = num[cur] + siz[ch[cur][0]] + siz[ch[cur][1]];
}
void rotate(int &cur, int k) {
    int fa = ch[cur][k^1];
    ch[cur][k^1] = ch[fa][k], ch[fa][k] = cur;
    maintain(cur), maintain(fa), cur = fa;
}
void insert(int &cur, int x) {
    if (!cur) newNode(cur, x);
    else {
        int k = cmp(cur, x);
        if (k == -1) ++num[cur];
        else {
            insert(ch[cur][k], x);
            if (rnd[ch[cur][k]] > rnd[cur]) rotate(cur, k ^ 1);
        }
        maintain(cur);
    }
}
void del(int &cur, int x) {
    int k = cmp(cur, x);
    if (k == -1) {
        if (num[cur] > 1) --num[cur];
        else {
            if (!ch[cur][0]) cur = ch[cur][1];
            else if (!ch[cur][1]) cur = ch[cur][0];
            else {
                int kk = rnd[ch[cur][0]] < rnd[ch[cur][1]] ? 0 : 1;
                rotate(cur, kk), del(ch[cur][kk], x);
            }
        }
    } else del(ch[cur][k], x);
    maintain(cur);
}
int rank(int cur, int x) { //x小的数的个数
    if (!cur) return 0;
    if (x == val[cur]) return siz[ch[cur][0]];
    if (x < val[cur]) return rank(ch[cur][0], x);
    return rank(ch[cur][1], x) + siz[ch[cur][0]] + num[cur];
}
int pre(int cur, int x) {
    if (!cur) return -INF;
    if (val[cur] >= x) return pre(ch[cur][0], x);
    return max(val[cur], pre(ch[cur][1], x));
}
int suf(int cur, int x) {
    if (!cur) return INF;
    if (val[cur] <= x) return suf(ch[cur][1], x);
    return min(val[cur], suf(ch[cur][0], x));
}
//----- Adorable Line -----
void build(int cur, int l, int r, int p, int x) {
    insert(root[cur], x);
    if (l == r) return;
    int mid = l + (r - l >> 1);
    if (p <= mid) build(cur << 1, l, mid, p, x);
    else build(cur << 1 | 1, mid + 1, r, p, x);
}
int Rank(int cur, int l, int r, int L, int R, int x) {
    if (L <= l && r <= R) return rank(root[cur], x);
    int mid = l + (r - l >> 1), res = 0;
    if (L <= mid) res += Rank(cur << 1, l, mid, L, R, x);
    if (mid < R) res += Rank(cur << 1 | 1, mid + 1, r, L, R, x);
    return res;
}
int Kth(int L, int R, int x) {
    int l = 0, r = 1e8, res = 0;
    while (l <= r) {
        int mid = l + (r - l >> 1);
        int rk = Rank(1, 1, n, L, R, mid);
        if (rk < x) l = mid + 1, res = mid;
        else r = mid - 1;
    }
    return res;
}
void update(int cur, int l, int r, int p, int x) {
    del(root[cur], a[p]);
    insert(root[cur], x);
    if (l == r) return;
    int mid = l + (r - l >> 1);
    if (p <= mid) update(cur << 1, l, mid, p, x);
    else update(cur << 1 | 1, mid + 1, r, p, x);
}
int Pre(int cur, int l, int r, int L, int R, int x) {
    if (L <= l && r <= R) return pre(root[cur], x);
    int mid = l + (r - l >> 1), res = -INF;
    if (L <= mid) res = Pre(cur << 1, l, mid, L, R, x);
    if (mid < R) res = max(res, Pre(cur << 1 | 1, mid + 1, r, L, R, x));
    return res;
}
int Suf(int cur, int l, int r, int L, int R, int x) {
    if (L <= l && r <= R) return suf(root[cur], x);
    int mid = l + (r - l >> 1), res = INF;
    if (L <= mid) res = Suf(cur << 1, l, mid, L, R, x);
    if (mid < R) res = min(res, Suf(cur << 1 | 1, mid + 1, r, L, R, x));
    return res;
}

int main() {
    n = read(); int m = read();
    for (int i = 1; i <= n; ++i) a[i] = read(), build(1, 1, n, i, a[i]);
    while (m--) {
        int opt = read();
        if (opt == 1) {
            int l = read(), r = read(), x = read();
            printf("%d\n", Rank(1, 1, n, l, r, x) + 1);
        } else if (opt == 2) {
            int l = read(), r = read(), x = read();
            printf("%d\n", Kth(l, r, x));
        } else if (opt == 3) {
            int p = read(), x = read();
            update(1, 1, n, p, x); a[p] = x;
        } else if (opt == 4) {
            int l = read(), r = read(), x = read();
            printf("%d\n", Pre(1, 1, n, l, r, x));
        } else {
            int l = read(), r = read(), x = read();
            printf("%d\n", Suf(1, 1, n, l, r, x));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Milkyyyyy/article/details/81368891