[BZOJ 2333] 棘手的操作 可并堆

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ 2333] 棘手的操作 可并堆相关的知识,希望对你有一定的参考价值。

实现

  1. 可并堆

    1.1. 可并堆的树高并不是 O(log n) 的.

      例如我来一个极端数据, 从前往后逐个插入:  n n-1 n-2 ... 5 4 3 2 1 

    1.2. c[N][2], par[N] 的维护技巧

      1.2.1. 注意两者是绑在一起的, 维护一个的时候要同时维护另一个.

      1.2.2. 注意是否存在儿子, 是否存在父亲, 否则 par[0] = x , 就会导致一系列可怕的问题.

  2. multiset

    对于 int 类型的变量 x , erase(x) 表示删除权值为 x 的所有元素.

    对于 map<int>::iterator 类型的迭代器 it , erase(it) 表示删除 it 这个元素.

    如果要删除一个元素, 我们考虑  multiset<int>::iterator it = Set.find(x)  +  Set.erase(it)  .

 

  最终实现:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <set>
using namespace std;
#define F(i, a, b) for (register int i = (a); i <= (b); i++)
namespace Input {
    const int S = 2000000;
    char s[S], *h = s+S, *t = h;
    inline char getchr(void) { if (h == t) fread(s, 1, S, stdin), h = s; return *h++; }
    inline int rd(void) {
        int f = 1; char c = getchr(); for (; !isdigit(c); c = getchr()) if (c == -) f = -1;
        int x = 0; for (; isdigit(c); c = getchr()) x = x*10+c-0; return x*f;
    }
    inline char rdc(void) { char c = getchr(); for (; !isalpha(c) && !isdigit(c); c = getchr()); return c; }
}
using Input::rd;
using Input::rdc;

const int N = 300005;

int n;
int c[N][2], par[N], Maxdep[N], key[N], tag[N];
int Unit[N], Root[N];
multiset<int> Set;
int Delta;

#define LC (c[x][0])
#define RC (c[x][1])

inline void Down(int x, int D) { key[x] += D, tag[x] += D; }
inline void Clear(int x) {
    if (tag[x] != 0) {
        if (LC > 0) Down(LC, tag[x]);
        if (RC > 0) Down(RC, tag[x]);
        tag[x] = 0;
    }
}
inline void Path(int x) {
    static int List[N]; int tot = 0;
    for (int i = x; i > 0; i = par[i])
        List[++tot] = i;
    for (; tot > 0; List[tot--] = 0)
        Clear(List[tot]);
}
inline void Up(int x) { 
    if (Maxdep[LC] < Maxdep[RC]) swap(LC, RC);
    Maxdep[x] = Maxdep[LC] + 1;
}

inline int Merge(int x, int y) {
    if (!x || !y) return x+y;
    if (key[x] < key[y]) swap(x, y);
    Clear(x);
    RC = Merge(RC, y), par[RC] = x;
    Up(x);
    return x;
}

inline void unLink(int x) { LC = RC = par[x] = Maxdep[x] = 0; }
inline void Split(int &rt, int x) {
    Path(x);
    if (rt == x) {
        rt = Merge(LC, RC);
        par[rt] = 0;
    }
    else {
        int t = Merge(LC, RC);
        if (t > 0) par[t] = par[x];
        c[par[x]][c[par[x]][1] == x] = t;
        for (int i = par[x]; i > 0; i = par[i])
            Up(i);
    }
    unLink(x);
}

inline int Find(int x) {
    static int List[N]; int tot = 0;
    for (; x != Unit[x]; x = Unit[x])
        List[++tot] = x;
    for (; tot > 0; List[tot--] = 0)
        Unit[List[tot]] = x;
    return x;
}

void Travel(void) {
    for (multiset<int>::iterator it = Set.begin(); it != Set.end(); it++)
        printf("%d ", *it);
}
inline void Erase(int x) {
    multiset<int>::iterator it = Set.find(x);
    Set.erase(it);
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("bzoj2333.in", "r", stdin);
    #endif
    
    n = rd();
    F(i, 1, n) {
        key[i] = rd();
        Unit[i] = Root[i] = i;
        Set.insert(key[i]);
    }
    
    int m = rd();
    F(Op, 1, m) {
        char c = rdc();
        if (c == U) {
            int x = rd(), y = rd();
            x = Find(x), y = Find(y);
            if (x == y) continue;
            Erase(key[Root[x]]), Erase(key[Root[y]]);
            Unit[x] = y, Root[y] = Merge(Root[x], Root[y]);
            Set.insert(key[Root[y]]);
        }
        else if (c == A) {
            c = rdc();
            if (c == 1) {
                int x = rd(), v = rd();
                int fx = Find(x);
                Erase(key[Root[fx]]);
                Split(Root[fx], x);
                key[x] += v;
                Root[fx] = Merge(Root[fx], x);
                Set.insert(key[Root[fx]]);
            }
            else if (c == 2) {
                int x = rd(), v = rd();
                x = Find(x);
                Erase(key[Root[x]]);
                Down(Root[x], v);
                Set.insert(key[Root[x]]);
            }
            else Delta += rd();
        }
        else {
            c = rdc();
            if (c == 1) {
                int x = rd();
                Path(x);
                printf("%d\n", key[x] + Delta);
            }
            else if (c == 2) {
                int x = rd();
                x = Find(x);
                printf("%d\n", key[Root[x]] + Delta);
            }
            else {
                multiset<int>::iterator it = Set.end(); it--;
                printf("%d\n", *it + Delta);
            }
        }
    }
    
    return 0;
}

 

以上是关于[BZOJ 2333] 棘手的操作 可并堆的主要内容,如果未能解决你的问题,请参考以下文章

真--可并堆模板--BZOJ2333: [SCOI2011]棘手的操作

BZOJ 2333 SCOI2011 棘手的操作 并查集+可并堆

bzoj2333[SCOI2011]棘手的操作 可并堆+STL-set

bzoj2333 SCOI2011—棘手的操作

bzoj2333 & luoguP3273棘手的操作(线段树合并)

bzoj 2333