hdu 2818(并查集,带权更新)

Building Block

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4420    Accepted Submission(s): 1372


Problem Description
John are playing with blocks. There are N blocks (1 <= N <= 30000) numbered 1...N。Initially, there are N piles, and each pile contains one block. Then John do some operations P times (1 <= P <= 1000000). There are two kinds of operation:

M X Y : Put the whole pile containing block X up to the pile containing Y. If X and Y are in the same pile, just ignore this command.
C X : Count the number of blocks under block X

You are request to find out the output for each C operation.
 

 

Input
The first line contains integer P. Then P lines follow, each of which contain an operation describe above.
 

 

Output
Output the count for each C operations in one line.
 

 

Sample Input
6 M 1 6 C 1 M 2 4 M 2 6 C 3 C 4
 

 

Sample Output
1 0 2
 
越来越觉得并查集牛了。。
 
题目大意:有N个piles(按序编号),每次有两种操作:
M x y 把包含x的一堆放到包含y的一堆上,如果xy同在一堆上,不做处理
C x 询问在x之下有多少个方块
 
题解:在以前的father和count(friend)之上再添加一个新的数组 under 表示当前结点的下面的pile的个数(我的理解是每个点带有一个权值为under[pos])
under数组的更新:第一种是针对每次将x堆放在y堆上面时,under[x]= under[x]+count[y]
第二种是求 a的根节点x与a之间的pile的个数,这里要利用find函数来进行递归,under[deep] = under[deep]+under[deep+1]
最后回溯到a点时就可以将under[a]求出来了
 
代码:
import java.util.Scanner;

public class Main {
    static int[] father;
    static int[] count;
    static int[] under;// 编号为i的Pile下面有多少个Piles

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        father = new int[30005];
        count = new int[30005];
        under = new int[30005];
        for (int i = 0; i < 30005; i++) {
            father[i] = i;
            count[i] = 1;
        }
        int n = sc.nextInt();
        while (n-- > 0) {
            String str = sc.next();
            if (str.equals("M")) {
                int a = sc.nextInt();
                int b = sc.nextInt();
                int x = find(a); // 找到的是a堆最下面的pile x
                int y = find(b); // 找到的是b堆最下面的pile y
                if (x != y) {
                    father[x] = y;
                    under[x] += count[y]; // 根节点下面的pile就是y堆所有的个数
                    count[y] += count[x]; // 更新当前堆的pile的个数
                }
            } else {
                int a = sc.nextInt();
                find(a);
                System.out.println(under[a]);
            }
        }

    }

    private static int find(int a) {
        if (father[a] != a) {   //这步非常精彩 从 a点开始向下递归 ,每向下递归一层其上层就是等于 下层的under[dep+1]加上自己的under[dep]
                                //到最后回溯到a点就把所有的都求出来了
            int tmp = find(father[a]);   
            under[a] += under[father[a]];
            father[a] = tmp;
        }
        return father[a];
    }
}

 

posted @ 2016-03-25 19:18  樱花庄的龙之介大人  阅读(300)  评论(0编辑  收藏  举报