| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
发一段有注释的代码纪念学习的第一道并查集原作者选择了非递归的方法,对于我这种菜菜来说,开始费了一些力气.
#include<stdio.h>
#include<stdlib.h>
const int maxn=30002;
int p[maxn],num[maxn],sum[maxn];
void Makeset(int x)
{
p[x]=-1;//根节点 ,上面的结点?
num[x]=0;//下家多少 ,或者距离root多远
sum[x]=1;//堆的大小
}
int Find(int x)//非递归压缩路径
{
int r=x,s;
s=0;
while(p[r]!=-1)//r为根结点
{
r=p[r];
s=s+num[r];
}
s=s-num[r];//这一步操作使s成为一堆负数数的和——距离root的和
while(x!=r)
{
int q=p[x];//q为x的父节点
p[x]=r;
num[x]=s+num[x];//更新num[x],使num[x]的性质得以满足,
s=s-num[q];
if(s==0)//更新到不需要更新为止
break;
x=q;
}
return r;
}
int Union(int a,int b)//Move操作
{
int t1,t2;
t1=Find(a);
t2=Find(b);
p[t2]=t1;
sum[t1]+=sum[t2];//sum[x]表示该堆的个数
num[t1]=num[t1]+sum[t2];//显然num值为自己的加后来的
num[t2]=num[t2]-num[t1];////距离root
// printf("num[t2]:%d\n",num[t2]);
return 0;
}
int count(int x)
{
int r,s;
r=Find(x);
s=0;
while(x!=-1)//只可能有run once& twice两种可能
{
s=s+num[x];
x=p[x];//x的上家成为x,上倒腾。
}
return s;
}
int main()
{
int i,t,x,y;
char ch[3];
for(i=1;i<=30000;i++)
Makeset(i);//堆初始化
scanf("%d",&t);
while(t--)
{
scanf("%s",ch);
if(ch[0]=='M')
{
scanf("%d%d",&x,&y);
Union(x,y);
}
else
{
scanf("%d",&x);
printf("%d\n",count(x));
}
}
return 0;
}
Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator