POJ 1988 Cube Stacking || HDU 2818 Building Block 带权并查集

来源:互联网 发布:js怎么判断对象为空 编辑:程序博客网 时间:2024/06/06 03:06

题目:

http://poj.org/problem?id=1988

题意:

有n个箱子,标号为1~n,初始时分成n堆,每堆一个按顺序。现在有p个操作,操作分两种:
- M x y:把x所在的那一堆放到y所在的那一堆上
- C x:查询x下面有多少个箱子
poj和hdu不同的一点是:hdu可能出现x y在同一堆的情况

思路:

定义rnk[x]为x到父节点的距离,num[x]为以x为祖先的所有点的个数。执行M操作时,首先找出x、y的祖先fx、fy,然后把fy作为fx的祖先,可以发现原本应该在x下面的箱子,在这样的表示下被扔到了x的上面,也就是倒着来的,这样执行查询操作时,x到祖先节点的距离就是答案。我们再来看fx和fy合并时距离怎么确定,已知fy是父节点,那么fx到fy的距离就应该是num[fy],仔细想一下便知,然后在更新num[fy],因为合并了fx及其子孙后点数就变了,当时把fx到fy的距离这个地方算错了,套用了带权并查集计算种类之间关系的式子,错的离谱。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#include <set>using namespace std;const int N = 30000 + 10, INF = 0x3f3f3f3f;int par[N], rnk[N], num[N];void init(){    for(int i = 0; i < N; i++) par[i] = i, num[i] = 1, rnk[i] = 0;}int ser(int x){    if(x != par[x])    {        int fx = ser(par[x]);        rnk[x] = rnk[x] + rnk[par[x]];        par[x] = fx;    }    return par[x];}void unite(int x, int y, int type){    int fx = ser(x), fy = ser(y);    if(fx == fy) return;    rnk[fy] = num[fx];    num[fx] += num[fy];    par[fy] = fx;}int main(){    int n, x, y;    char ch;    while(~ scanf("%d", &n))    {        init();        for(int i = 1; i <= n; i++)        {            scanf(" %c", &ch);            if(ch == 'M')            {                scanf("%d%d", &x, &y);                unite(y, x, 1);            }            else            {                scanf("%d", &x);                ser(x);                printf("%d\n", rnk[x]);            }        }    }    return 0;}
0 0