[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