SGU 263 Tower(平衡树+并查集)

题意:现有10^6个位置(cell),每个位置上可以放若干个cube,对于任意的两个数i<=j如果满足[i,j]之间任意位置都有cube且i-1和j+1没有箱子,则称[i,j]为一个Tower。
现有10^6条修改和查询,保证合法性:
  • put <x> <c> - put c cubes on cell x
  • tput <t> <x> <c> - put c cubes on column x in tower with number t (towers are numbered from left to the right)
  • towers - print total number of towers built
  • cubes <t> - print the number of cubes in the tower t
  • length <t> - print the length of the tower t
  • tcubes <t> <x> - print the number of cubes in column x of the tower t
解法:根据题意知,需要维护的统计量有:某个cell的cube数,某个tower的cube数,某个tower的长度,及tower数,第i个tower的左端点。只有第一种会改变tower的分布(产生新tower或合并若干个tower)由于tower的产生具有传递性因此很容易想到并查集维护(父节点相当于所在线段的左端点),Treap保存现有线段的左端点,产生tower时将左端点插入合并tower时将右侧左端点删除,这样便可以维护第i个tower的左端点。
#include<cstdio>
#include<cstdlib>
using namespace std;
#define maxn 1000010
struct TreeNode {
	int key;
	int left, right;
	int size;
	int pri;
	void init() {
		left = right = 0;
		size = 1;
		pri = rand();
	}
};

struct Treap {
	TreeNode nodes[maxn];
	int root, cnt, count;
	int stack[maxn], top;
	void init() {
		count = root = cnt = top = 0;
		nodes[0].pri = -0x7FFFFFFF;
	}
	int newnode() {
		int ret;
		if (top)
			ret = stack[--top];
		else
			ret = ++cnt;
		nodes[ret].init();
		return ret;
	}
	void push_up(int idx) {
		nodes[idx].size = nodes[nodes[idx].left].size
				+ nodes[nodes[idx].right].size + 1;
	}
	void leftRotate(int &root) {
		int tmp = nodes[root].right;
		nodes[root].right = nodes[nodes[root].right].left;
		nodes[tmp].left = root;
		push_up(root);
		push_up(tmp);
		root = tmp;
	}
	void rightRotate(int &root) {
		int tmp = nodes[root].left;
		nodes[root].left = nodes[nodes[root].left].right;
		nodes[tmp].right = root;
		push_up(root);
		push_up(tmp);
		root = tmp;
	}
	void insert(int k) {
		count++;
		insert(k, root);
	}
	void insert(int k, int& root) {
		if (!root) {
			root = newnode();
			nodes[root].key = k;
			return;
		} else if (k < nodes[root].key) {
			insert(k, nodes[root].left);
			if (nodes[nodes[root].left].pri > nodes[root].pri)
				rightRotate(root);
		} else {
			insert(k, nodes[root].right);
			if (nodes[nodes[root].right].pri > nodes[root].pri)
				leftRotate(root);
		}
		push_up(root);
	}
	void del(int k) {
		count--;
		del(root, k);
	}
	void del(int &root, int k) {
		if (nodes[root].key == k) {
			if (!nodes[root].left && !nodes[root].right) {
				stack[top++] = root;
				root = 0;
				return;
			}
			if (nodes[nodes[root].left].pri > nodes[nodes[root].right].pri) {
				rightRotate(root);
				del(nodes[root].right, k);
			} else {
				leftRotate(root);
				del(nodes[root].left, k);
			}
			push_up(root);
			return;
		}
		if (k < nodes[root].key)
			del(nodes[root].left, k);
		else
			del(nodes[root].right, k);
		push_up(root);
	}
	int select(int k) {
		return select(root, k);
	}
	int select(int root, int k) {
		int s = nodes[nodes[root].left].size;
		if (s >= k)
			return select(nodes[root].left, k);
		if (s + 1 == k)
			return nodes[root].key;
		return select(nodes[root].right, k - 1 - s);
	}
} tree;
int num[maxn], p[maxn];//每个点的cube数及所在线段的左端点
int count[maxn], len[maxn];//做端点为i的线段的cube数及长度
int n, t, x, c;
void init() {
	tree.init();
	for (int i = 0; i < maxn; i++) {
		len[i] = count[i] = num[i] = 0;
		p[i] = i;
	}
}
int find(int x) {
	if (x == p[x])
		return x;
	p[x] = find(p[x]);
	return p[x];
}
void put() {
	scanf("%d%d", &x, &c);
	if (num[x] == 0) {
		count[x] = num[x] = c;
		len[x] = 1;
		tree.insert(x);
		if (num[x + 1] != 0) {
			p[x + 1] = x;
			len[x] += len[x + 1];
			count[x] += count[x + 1];
			tree.del(x + 1);
		}
		if (num[x - 1] != 0) {
			tree.del(x);
			int px = find(x - 1);
			p[x] = px;
			len[px] += len[x];
			count[px] += count[x];
		}
	} else {
		int px = find(x);
		num[x] += c;
		count[px] += c;
	}
}

void tput() {
	scanf("%d%d%d", &t, &x, &c);
	int temp = tree.select(t);
	num[temp + x - 1] += c;
	count[temp] += c;
}
void towers() {
	int temp = tree.count;
	printf("%d towers\n", temp);
}
void cubes() {
	scanf("%d", &t);
	int temp = tree.select(t);
	printf("%d cubes in %dth tower\n", count[temp],t);
}
void length() {
	scanf("%d", &t);
	int temp = tree.select(t);
	printf("length of %dth tower is %d\n",t,len[temp]);
}
void tcubes() {
	scanf("%d%d",&t,&x);
	int temp = tree.select(t);
	printf("%d cubes in %dth column of %dth tower\n",num[temp+x-1],x,t);
}
int main() {
	char ch[10];
	scanf("%d", &n);
	init();
	while (n--) {
		scanf("%s", ch);
		if (ch[0] == 'p')
			put();
		if(ch[0]=='t'&&ch[1]=='p')
			tput();
		if(ch[0]=='t'&&ch[1]=='o')
			towers();
		if(ch[0]=='c')
			cubes();
		if(ch[0]=='l')
			length();
		if(ch[0]=='t'&&ch[1]=='c')
			tcubes();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值