zoukankan      html  css  js  c++  java
  • POJ 1988 Cube Stacking (带权并查集)

    Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes labeled 1 through N. They start with N stacks, each containing a single cube. Farmer John asks Betsy to perform P (1<= P <= 100,000) operation. There are two types of operations:
    moves and counts.

    • In a move operation, Farmer John asks Bessie to move the stack containing cube X on top of the stack containing cube Y.
    • In a count operation, Farmer John asks Bessie to count the number of cubes on the stack with cube X that are under the cube X and report that value.

    Write a program that can verify the results of the game.
    Input

    • Line 1: A single integer, P

    • Lines 2..P+1: Each of these lines describes a legal operation. Line 2 describes the first operation, etc. Each line begins with a 'M' for a move operation or a 'C' for a count operation. For move operations, the line also contains two integers: X and Y.For count operations, the line also contains a single integer: X.

    Note that the value for N does not appear in the input file. No move operation will request a move a stack onto itself.
    Output
    Print the output from each of the count operations in the same order as the input file.
    Sample Input
    6
    M 1 6
    C 1
    M 2 4
    M 2 6
    C 3
    C 4
    Sample Output
    1
    0
    2

    题意:

    起初有N个方块堆,有两种操作,M是移动含有X的方块堆到含有Y的方块堆上,C是计算有多少个方块堆在X的下面。

    题解:

    经典好题! 很容易想到用并查集来维护移动后方块堆的关系,但是怎么维护方块之间的顺序关系呢,或者说怎么知道某个方块下面有多少个方块呢?我们可以开个dis数组记录方块到根节点的距离,num数组记录当前堆中方块数量。假设有A->B->C从高到底的三个方块,那么dis[A->C]=dis[B->C]+dis[A->B]。需要注意的是路径压缩的时候,递归求节点到根节点的距离,具体请看代码。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    const int maxn=3e4+5;
    int par[maxn];
    int dis[maxn],num[maxn];//dis为到根节点的距离,只有当该结点直接连接根节点时,这个值才有效。
    //num[i]为i所在的堆的所有立方体数量
    void init()
    {
        for(int i=0;i<=maxn;i++)
            par[i]=i,dis[i]=0,num[i]=1;
    }
    int find(int x)
    {
        if(par[x]==x)
            return x;
        int fa=par[x];//
        par[x]=find(par[x]);//路径压缩,注意这两步,一定要理解递归
        dis[x]+=dis[fa];//此时x的父亲节点已经连接到根节点上了
        return par[x];
    }
    void unite(int x,int y)
    {
        x=find(x),y=find(y);
        if(x==y)
            return ;
        par[x]=y;
        dis[x]+=num[y];
        num[y]+=num[x];//两个堆合并
    }
    int main()
    {
        init();
        int n;
        cin>>n;
        while(n--)
        {
            char op;
            cin>>op;
            if(op=='M')
            {
                int x,y;
                cin>>x>>y;
                unite(x,y);
            }
            else
            {
                int x;
                cin>>x;
                find(x);//输出前对dis[a]进行更新
                cout<<dis[x]<<endl;
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Linq聚合操作之Aggregate,Count,Sum,Distinct源码分析
    Linq分区操作之Skip,SkipWhile,Take,TakeWhile源码分析
    Linq生成操作之DefautIfEmpty,Empty,Range,Repeat源码分析
    Linq基础操作之Select,Where,OrderBy,ThenBy源码分析
    PAT 1152 Google Recruitment
    PAT 1092 To Buy or Not to Buy
    PAT 1081 Rational Sum
    PAT 1084 Broken Keyboard
    PAT 1077 Kuchiguse
    PAT 1073 Scientific Notation
  • 原文地址:https://www.cnblogs.com/orion7/p/7953638.html
Copyright © 2011-2022 走看看