BZOJ 2733: [HNOI2012]永无乡(平衡树启发式合并) - Gemini Boy - ACM之路~
BZOJ 2733: [HNOI2012]永无乡(平衡树启发式合并)
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2733
这题我是用treap做的,每个岛代表一个节点,每个节点维护一颗treap,然后节点之间用并查集维护,合并的时候比较俩个节点在并查集中的根的treap的节点个数,从小的向大的暴力insert进去,就行了。0.0
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <map> #include <vector> #include <set> using namespace std; template <class T> inline void scan(T &ret) { char c; ret = 0; while ((c = getchar()) < '0' || c > '9') ; while (c >= '0' && c <= '9') ret = ret * 10 + (c - '0'), c = getchar(); } const int maxn = 100100; struct TreeNode { TreeNode *L, *R; int num; int size; int pri; int key; }; TreeNode nodes[maxn*30], stack[maxn*5]; TreeNode *null; int C, Top; void init() { C = 0; Top = 0; null = &nodes[C++]; null->L = null->R = null; null->pri = -0x7FFFFFFF; null->size = 0; null->key = 0; null->num = 0; } struct Treap { TreeNode* root; vector<TreeNode*> list; void init() { root = null; } void toArrayList(TreeNode* root) { if (root != null) { toArrayList(root->L); list.push_back(root); toArrayList(root->R); } } TreeNode* newNode(int key, int num) { TreeNode* ret; if (Top) ret = &stack[--Top]; else ret = &nodes[++C]; ret->L = ret->R = null; ret->key = key; ret->pri = rand(); ret->num = num; ret->size = num; return ret; } TreeNode* merge(TreeNode* small, TreeNode* large) { if (small == null) return large; if (large == null) return small; if (small->pri < large->pri) { small->R = merge(small->R, large); pushUp(small); return small; } else { large->L = merge(small, large->L); pushUp(large); return large; } } pair<TreeNode*, TreeNode*> split(TreeNode* root, int key) { pair<TreeNode*, TreeNode*> tmp; if (root == null) { tmp = make_pair(null, null); return tmp; } if (key <= root->key) { tmp = split(root->L, key); root->L = tmp.second; pushUp(root); tmp.second = root; return tmp; } else { tmp = split(root->R, key); root->R = tmp.first; pushUp(root); tmp.first = root; return tmp; } } TreeNode* upperBound(TreeNode* root, int key) { TreeNode* ans = null; TreeNode* i = root; while (i != null) { if (key < i->key) { ans = i; i = i->L; } else { i = i->R; } } return ans; } TreeNode* lowerBound(TreeNode* root, int key) { TreeNode* ans = null; TreeNode* i = root; while (i != null) { if (key < i->key) { i = i->L; } else { ans = i; i = i->R; } } return ans; } bool contains(TreeNode* root, int key) { if (root == null) return false; if (key == root->key) return true; else if (key < root->key) return contains(root->L, key); else return contains(root->R, key); } void insert(TreeNode* root, int key, int num) { if (key < root->key) insert(root->L, key, num); else if (key == root->key) root->num += num; else insert(root->R, key, num); pushUp(root); } void insert(int key, int num) { if (contains(root, key)) { insert(root, key, num); return ; } pair<TreeNode*, TreeNode*> tmp = split(root, key); TreeNode* node = newNode(key, num); root = merge(merge(tmp.first, node), tmp.second); } void del(int key) { pair<TreeNode*, TreeNode*> tmp = split(root, key); TreeNode* node = upperBound(tmp.second, key); if (node == null) root = tmp.first; else root = merge(tmp.first, split(tmp.second, node->key).second); } void del(TreeNode* root, int key) { if (!contains(root, key)) return ; if (key < root->key) del(root->L, key); else if (key == root->key) { root->num--; if (root->num == 0) del(key); } else { del(root->R, key); } pushUp(root); } TreeNode* select(TreeNode* root, int k) { if (k <= root->L->size) return select(root->L, k); else if (k >= root->L->size + 1 && k <= root->L->size + root->num) return root; else return select(root->R, k-root->L->size-root->num); } int getMin(TreeNode* root, int key) { if (key < root->key) return getMin(root->L, key); else if (key == root->key) return root->L->size + root->num; else return root->L->size + root->num + getMin(root->R, key); } int getMax(TreeNode* root, int key) { if (key < root->key) return root->R->size + root->num + getMax(root->L, key); else if (key == root->key) return root->R->size + root->num; else return getMax(root->R, key); } int size() { return root->size; } void visit(TreeNode* root) { if (root != null) { printf("key: %d num: %d size: %d\n", root->key, root->num, root->size); visit(root->L); visit(root->R); } } void pushUp(TreeNode* x) { x->size = x->L->size + x->R->size + x->num; } }; Treap tree[maxn]; char op[10]; int n, m, q, hash[maxn], arr[maxn]; int par[maxn]; int find(int x) { if (par[x] != x) par[x] = find(par[x]); return par[x]; } void merge(int x, int y) { int px = find(x); int py = find(y); if (px != py) { if (tree[px].size() < tree[py].size()) { par[px] = py; tree[px].list.clear(); tree[px].toArrayList(tree[px].root); for (int i = 0; i < tree[px].list.size(); i++) { TreeNode* tmp = tree[px].list[i]; tree[py].insert(tmp->key, tmp->num); } } else { par[py] = px; tree[py].list.clear(); tree[py].toArrayList(tree[py].root); for (int i = 0; i < tree[py].list.size(); i++) { TreeNode* tmp = tree[py].list[i]; tree[px].insert(tmp->key, tmp->num); } } } } int query(int x, int k) { int px = find(x); if (tree[px].size() < k) return -1; else return tree[px].select(tree[px].root, k)->key; } void work() { init(); scan(n); scan(m); // scanf("%d %d", &n, &m); for (int i = 0; i <= n; i++) tree[i].init(); for (int i = 0; i <= n; i++) par[i] = i; for (int i = 1; i <= n; i++) { scan(arr[i]); // scanf("%d", &arr[i]); hash[arr[i]] = i; } for (int i = 1; i <= n; i++) tree[i].insert(arr[i], 1); for (int i = 1; i <= m; i++) { int x, y; scan(x); scan(y); // scanf("%d %d", &x, &y); merge(x, y); } } void run() { scanf("%d", &q); for (int i = 1; i <= q; i++) { int x, y; scanf("%s", op); scan(x); scan(y); // scanf("%s %d %d", op, &x, &y); if (op[0] == 'Q') { int ans = query(x, y); if (ans != -1) ans = hash[ans]; printf("%d\n", ans); } else { merge(x, y); } } } int main() { work(); run(); }