[原创题] max 左偏树

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[原创题] max 左偏树相关的知识,希望对你有一定的参考价值。

Simple

   你要维护一个多重集合 $S$ .

  ? 最初集合为空.

  ? 一共有 $m$ 次操作, 每次操作形如下面两种中的一种:

    ? $1~a$ : 在多重集合 $S$ 中插入一个 $a$ .

    ? $2$ : 查询 $\max_{i \in S}i$ .

  ? $m \le {10} ^ 5, a \le {10} ^ 9$ , 强制在线.

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
using namespace std;

#define F(i, a, b) for (register int i = (a); i <= (b); i++)

const int N = 100005;

int m;
int rt, tot, c[N][2], d[N], key[N];

inline int rd(void) {
    int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1;
    int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f;
}

inline int Newnode(int w) { return d[++tot] = 1, key[tot] = w, tot; }
inline void Merge(int &x, int y) {
    if (!x) { x = y; return; }
    if (!y) return;
    if (key[x] < key[y]) { int t = x; x = y, y = t; }
    Merge(c[x][1], y);
    if (d[c[x][0]] < d[c[x][1]]) swap(c[x][0], c[x][1]);
    d[x] = d[c[x][1]] + 1;
}

int main(void) {
    m = rd();
    F(i, 1, m) {
        int k = rd();
        if (k == 1) {
            int w = rd();
            int t = Newnode(w);
            Merge(rt, t);
        }
        else printf("%d\n", key[rt]);
    }    
    return 0;
}

 

Normal

  ? 你要维护一个多重集合 $S$ .

  ? 最初集合为空.

  ? 一共有 $m$ 次操作, 每次操作形如下面两种中的一种:

    ? $1~a$ : 在多重集合 $S$ 中插入一个 $a$ .

    ? $2$ : 查询 $\max_{i \in S}i$ .

    ? $3~a$ : 在多重集合 $S$ 中删除一个 $a$ .

  ? $m \le {10} ^ 5, a \le {10} ^ 9$ , 强制在线.

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <vector>
#include <map>
using namespace std;

#define F(i, a, b) for (register int i = (a); i <= (b); i++)

const int N = 100005;

int m;
map<int, int> id; int ind; vector<int> g[N];
int rt, tot, c[N][2], par[N], d[N], key[N];

inline int rd(void) {
    int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1;
    int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f;
}

inline int Newnode(int w) { return d[++tot] = 1, key[tot] = w, tot; }
inline void Merge(int &x, int y) {
    if (!x) { x = y; return; }
    if (!y) return;
    if (key[x] < key[y]) { int t = x; x = y, y = t; }
    Merge(c[x][1], y), par[c[x][1]] = x;
    if (d[c[x][0]] < d[c[x][1]]) swap(c[x][0], c[x][1]);
    d[x] = d[c[x][1]] + 1;
}
inline void Insert(int w) {
    int t = Newnode(w);
    Merge(rt, t);
    int ID = !id[w] ? id[w] = ++ind : id[w];
    g[ID].push_back(t);
}
inline void Delete(int w) {
    int ID = id[w], t = g[ID].back(); g[ID].pop_back();
    if (t == rt) {
        int L = c[rt][0], R = c[rt][1];
        par[L] = c[rt][0] = par[R] = c[rt][1] = 0;
        Merge(L, R), rt = L;
    }
    else {
        int L = c[t][0], R = c[t][1], A = par[t];
        par[L] = c[t][0] = par[R] = c[t][1] = par[t] = c[A][c[A][1] == t] = 0;
        for (; par[A] > 0; A = par[A]) {
            if (d[c[A][0]] < d[c[A][1]]) swap(c[A][0], c[A][1]);
            d[A] = d[c[A][1]] + 1;
        }
        Merge(L, R);
        Merge(rt, L);
    }
}

int main(void) {
    m = rd();
    F(i, 1, m) {
        int k = rd();
        if (k == 1) {
            int w = rd();
            Insert(w);
        }
        else if (k == 2)
            printf("%d\n", key[rt]);
        else {
            int w = rd();
            Delete(w);
        }
    }
    
    return 0;
}

 

Normal 2

  支持可持久化.

inline int Merge(int x, int y) {
    if (!x || !y) return x + y;
    if (key[x] < key[y]) swap(x, y);
    int t = Copynode(x);
    c[t][1] = Merge(c[x][1], y);
    if (d[c[t][0]] < d[c[t][1]]) swap(c[t][0], c[t][1]);
    d[t] = d[c[t][1]] + 1;
    return t;
}

 

以上是关于[原创题] max 左偏树的主要内容,如果未能解决你的问题,请参考以下文章

p3273 棘手的操作(左偏树)

[洛谷P3261] [JLOI2015]城池攻占(左偏树)

P3273 [SCOI2011]棘手的操作 左偏树

模板左偏树

左偏树(p1456) 比较模板的一道题

罗马游戏(左偏树)