【题目链接】:Click here~~
【题意】:
给 n 块砖头,开始各为一堆,两种操作:
1、把 X 所在的那一堆箱子里的砖头放到 Y 所在的那一堆上面。
2、询问 X 下面有多少块砖。
【解题思路】:好像大家都叫它带权并查集,那为了方便,这里也这样叫吧,因为涉及前面的和后面的箱子个数,对应的查找操作,一开始想用结构体来写,在结构体里定义每个箱子的前驱和后继,每次输入的时候统计一下相应的前驱和后继的个数,后来发现不行,因为涉及到合并操作,比如说M 2 4 M 2 6连续出现两个2,用结构体是不容易实现的,这时候发挥并查集的效果了,在合并的时候分别更新 (1)Sum[i]=1;//i所在的箱子总数,(2)upsum[i]=0;//i下面箱子数,最后C
a时直接输出upsum[a]
代码:
/* Author:HRW 带权并查集 */ #include <bits/stdc++.h> using namespace std; const int N=30005; int father[N],Sum[N],upsum[N],n,m,a,b,T; char ch[4]; int find(int x){ if(x!=father[x]){ int temp=find(father[x]); upsum[x]+=upsum[father[x]]; father[x]=temp; } return father[x]; } void Union(int a,int b) { int pa=find(a); int pb=find(b); if(pa!=pb){ upsum[pa]=Sum[pb];//合并pa下面pb的所有箱子 Sum[pb]+=Sum[pa];//pb所在的堆的箱子总数 father[pa]=pb;//合并根节点 } } void init(){ for(int i=0; i<N; i++) { father[i]=i; Sum[i]=1;//i所在的箱子总数 upsum[i]=0;//i下面箱子数 } } int main() { while(scanf("%d",&T)!=EOF){ init(); for(int i=0; i<T; i++){ scanf("%s",ch); if(ch[0]=='M'){ scanf("%d%d",&a,&b); Union(a,b); } else{ scanf("%d",&a); find(a); printf("%d\n",upsum[a]); } } } return 0; }
时间: 2024-11-12 08:44:10