【ZCMU1930】帽子戏法(并查集)

题目链接

1930: 帽子戏法

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 88  Solved: 24
[Submit][Status][Web Board]

Description

小A家有很多很多顶帽子初始时帽子都是独立分开的,每顶帽子都有一个编号用于区分.小A会有以下操作之一:
1.将编号为y的帽子所在的帽子堆放在编号为x的帽子所在的帽子堆顶上,如果x,y在同一堆则不做任何动作.
2.小A会向你询问编号为x的帽子上方有多少只帽子.

Input

输入有多组数据:
第一行输入N,M分别为帽子数和操作数(1<=N<=40000,1<=M<=400000)
帽子的编号对应1,2,3...,N.
接下来有M行输入为 T x y 对应操作1. Q x 对应操作2.

Output

对于小A的询问输出位于编号为x的帽子上方的帽子数.

Sample Input

2 2

T 1 2

Q 1

扫描二维码关注公众号,回复: 3619181 查看本文章

Sample Output

1

HINT

Source

lcf

【解题思路】

num[i]:每个帽子上的帽子数

pos[i]:每个帽子堆的帽子数,i 是这堆帽子的最上面的帽子编号

需要注意的是在每一次合并的时候是把两个根节点合并,也就是说num数组只更新该点到根节点那条路径上的值,但是根节点的其他儿子节点并没有被更新,所以在查询的时候,需要再用并查集遍历一遍查询节点的路径上的num。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=4e5+5;
int pre[maxn],num[maxn],pos[maxn];
//num表示每个帽子上的帽子数 pos表示每个帽子堆的帽子数
int findroot(int x)
{
    if(x!=pre[x])
    {
        int fx=pre[x];
        pre[x]=findroot(pre[x]);
        num[x]+=num[fx];
    }
    return pre[x];
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=0;i<=n;i++)
        {
            pre[i]=i;
            num[i]=0;
            pos[i]=1;
        }
        while(m--)
        {
	    char ch=getchar();
	    while(ch!='T'&&ch!='Q')ch=getchar();
            if(ch=='T')
            {
                int x,y;
                scanf("%d%d",&x,&y);
                int fx=findroot(x),fy=findroot(y);
                if(fx!=fy)
                {
                    pre[fx]=fy;
                    num[fx]+=pos[fy];
                    pos[fy]+=pos[fx];
                }
            }
            else
            {
                int x;
                scanf("%d",&x);
                findroot(x);
                printf("%d\n",num[x]);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39826163/article/details/83036231