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
【解题思路】
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;
}