BZOJ 2733: [HNOI2012]永无乡(平衡树启发式合并) - Gemini Boy - ACM之路~

BZOJ 2733: [HNOI2012]永无乡(平衡树启发式合并)

Gemini posted @ 2013年8月15日 22:52 in 题解 with tags 动态规划 bzoj , 1979 阅读

链接: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();
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter
Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee