带权并查集:
http://acm.hdu.edu.cn/showproblem.php?pid=3635
根据题意可得,我们要求某个球移动了多少次,一个城市有多少个球。
对于第二个问题很好解决,当我们用并查集并的时候,将子节点内的球全部赋给父节点,即num[parent]+=num[loof];
第一个问题才是大家纠结的。我们想一下,当将并查集的子节点连接到父节点时即表示子节点内的所有球都移动了一次,并查集最终形成的是一棵树,我们只需要求叶子节点到根节点的距离。叶子节点表示的是球开始的位置,根节点则是球现在所在的位置。这样我们就可以在并查集查原始父节点的时候来求,即每次都加上父节点到父节点的父节点的次数即可以求的。
#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX 10200
using namespace std;
int parent[MAX],Rank[MAX],num[MAX];
int n,m,flag;
void init()
{
for(int i=1; i<=n; i++)
{
Rank[i]=0;
num[i]=1;
parent[i]=i;
}
flag++;
}
int find(int x)
{
if(parent[x]!=x)
{
int temp=parent[x];
parent[x]=find(parent[x]);
Rank[x]+=Rank[temp]; //每次加上父节点到父节点的父节点的次数
}
return parent[x];
}
void Union(int a,int b)
{
int root_a=find(a),
root_b=find(b);
if(root_a==root_b) return;
parent[root_a]=root_b;
num[root_b]+=num[root_a]; //子节点的球的全部放到根节点上
num[root_a]=0; //子节点 上的球个数为0
Rank[root_a]=1; //对于每个子节点,并一次即移动一次。
}
void solve()
{
char ch[2];
int a,b;
printf("Case %d:\n",flag);
for(int i=1; i<=m; i++)
{
cin>>ch;
if(ch[0]=='T')
{
cin>>a>>b;
Union(a,b);
}
else
{
cin>>a;
find(a);
printf("%d %d %d\n",parent[a],num[parent[a]],Rank[a]);
}
}
}
int main()
{
int t;
cin>>t;
flag=0;
while(t--)
{
cin>>n>>m;
init();
solve();
}
return 0;
}
hdu 2818
http://acm.hdu.edu.cn/showproblem.php?pid=2818
这题数据太坑,说了1~N的,结果包含了0,坑啊
这道题与POJ1988一样
http://poj.org/problem?id=1988
#include <iostream>
#include <cstring>
#include <cstdio>
#define MAX 30100
using namespace std;
int parent[MAX],num[MAX],Rank[MAX];
int n;
void init()
{
for(int i=0; i<MAX; i++)
{
parent[i]=i;
num[i]=1; //表明树桩上有多少个石块
Rank[i]=0; //石块i下面有多少石块
}
}
int find(int x)
{
if(parent[x]!=x)
{
int temp=parent[x];
parent[x]=find(parent[x]);
Rank[x]+=Rank[temp];
}
return parent[x];
}
void Union(int a,int b)
{
int root_a=find(a),
root_b=find(b);
if(root_a==root_b) return;
parent[root_a]=root_b;
Rank[root_a]=num[root_b]; //让连接到根节点的节点的值等于根节点上的石块数目,这样可以在查操作的时候更新每个石块下有多少石块
num[root_b]+=num[root_a]; //将所有子节点上的石块移动到根节点
num[root_a]=0;
}
void solve()
{
char ch[2];
int a,b;
for(int i=1; i<=n; i++)
{
cin>>ch;
if(ch[0]=='M')
{
cin>>a>>b;
Union(a,b);
}
else
{
cin>>a;
find(a);
printf("%d\n",Rank[a]);
}
}
}
int main()
{
while(cin>>n)
{
init();
solve();
}
return 0;
}
本文探讨了并查集在解决特定问题时的应用与优化策略,包括如何通过并查集解决城市球移动次数与城市内球数量的问题。通过实例演示并查集在不同场景下的高效运用,特别强调了叶子节点到根节点距离的计算方法,以此揭示并查集在实际问题解决中的强大能力。
4092

被折叠的 条评论
为什么被折叠?



