1. 程式人生 > >POJ-1988 Cube Stacking (加權並查集)

POJ-1988 Cube Stacking (加權並查集)

題目大意:

給你編號從1到30000的大小相同的立方體,現在我有2種操作:

1.move 1,3表示把1放在3的上面。

還有一種情況是:假如1的下面還有一個2,3的下面還有一個4,那麼move1,3的意思就是把1所在的全部立方體放在3全部立方體的上面,而且保持原來1和3所在堆的立方體的順序。移動後從上到下依次為1,2,3,4.且只能是這一種情況

2.count 3 表示詢問3下面有幾個立方體

首先我們考慮它們摞在一起後順序不能變,只能整體移動,要詢問的是下面的立方體的個數。類似詢問根結點下面子結點的個數,所以我們可以考慮使用並查集來解決這道題,所以我們要用到pre陣列和son陣列,表示結點的父節點和這個結點的子結點總數,同時我們再開一個表示子節點到根節點的距離陣列,每次更新的時候只需把合併到根節點上的子節點的距離陣列更新為未合併前根節點含有立方體的個數;查詢的時候,只需要用根節點總數-離根結點的距離然後-1就可以求出這個結點下面的立方體的個數了。

    通過這道題, 我對並查集的路徑壓縮又有了一個新的認識, 我發現在有權值的並查集裡的路徑壓縮時候的其的權值的改變也只能在路徑壓縮時候進行改變, 其他時候不能對壓縮路徑的權值改變。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N = 30000+10;
struct node
{
    int parent;
    int dis;
    int son;
}p[N];
int findset(int x)
{
    if(p[x].parent == x)
        return x;
    int rootx = p[x].parent;
    p[x].parent = findset(rootx);//壓縮路徑
    p[x].dis += p[rootx].dis;//改變權值
    return p[x].parent;
}
int main()
{
    int T, x, y, c;
    char s;
    for(int i = 1; i < N; i++)
    {
        p[i].parent = i;
        p[i].dis = 0;
        p[i].son = 1;
    }
    scanf("%d", &T);
    while(T--)
    {
        scanf("%*c%c", &s);
        if(s == 'M')
        {
            scanf("%d%d", &x, &y);
            int rootx = findset(x);
            int rooty = findset(y);
            if(rootx != rooty)
            {
                p[rooty].parent = rootx;
                p[rooty].dis = p[rootx].son;//每次更新合併的子節點到根節點的距離
                p[rootx].son += p[rooty].son;//每次更新根節點的總數
            }
        }
        else
        {
            scanf("%d", &c);
            printf("%d\n", p[findset(c)].son-p[c].dis-1);
        }
    }
    return 0;
}