poj1988 Cube Stacking 带权并查集

题目链接:http://poj.org/problem?id=1988

题意:有n个方块,编号为1-n,现在存在两种操作:

  • M  i  j  将编号为i的方块所在的那一堆方块移到编号为j的方块所在的那一堆方块上方,方块原先的相对位置保持不变
  • C  i     计算在方块i下面有多少个方块

虽然知道这道题用并查集做,但并没什么思路。看了看题解:用h[i]维护当前方块到其父亲方块的距离,num[i]维护方块i所在的堆的方块数,每次合并(unite)时,将最下面的方块作为根节点,并更新新堆的木块数。每次查询路径压缩时,更新节点父亲的同时,也更新该节点到父亲(此时父亲即是根)的距离h[i],因此每次计算木块数目时,需要执行一次查询操作,将h[i]更新为到根的距离再输出

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
class union_find_set {
public:
	union_find_set(int n) {    //并查集初始化
		fa = new int[n];
		h = new int[n];
		num = new int[n];
		for (int i = 0; i < n; i++) {
			fa[i] = i;
			num[i] = 1;
			h[i] = 0;
		}
	}
	~union_find_set()
	{
		delete fa,h,num;
	};
	int find(int x) {    //查询函数
		if (fa[x] == x)
			return x;
		int t = fa[x];
		fa[x] = find(fa[x]);
		h[x] += h[t];
		return fa[x];
	}
	void unite(int x, int y) {    //合并函数
		x = find(x); 
		y = find(y);
		if (x != y) {
			fa[x] = y;
			h[x] = num[y];
			num[y] += num[x];
		}
	}
	bool same(int x, int y) {      //判断是否在一个堆
		if (find(x) == find(y))
			return 1;
		return 0;
	}
	int n;
	int *fa,*h,*num;
};

int main() {
	int n;
	scanf("%d", &n);
	getchar();
	//cout << n << endl;
	union_find_set cube(n + 1);
	for (int i = 1;i <= n;i++) {
		char c;
		scanf("%c", &c);
		//cout << c << -1 << endl;
		int a, b;
		if (c == 'M') {
			scanf("%d%d", &a, &b);
			cube.unite(a, b);
		}
		else {
			scanf("%d", &a);
			cube.find(a);
			printf("%d\n", cube.h[a]);
		}
		getchar();
	}
}

  

猜你喜欢

转载自www.cnblogs.com/dlutjwh/p/10710325.html