您的位置:首页 > 其它

带权并查集(hdu 3635,hdu 2818)

2013-09-25 10:54 190 查看
带权并查集:

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: