首先看到这个题号的时候我想起了好公民,韩寒同学和他的不死鸟= =
本人二蛋一枚,近日做了些并查集的东西但是一直不太明白怎么才能查节点路径,而且觉得要是迭代的时候加了r[x]的话会出现多加的情况,后来经网上高人指点(觉得还是好人多,虽然自己确实不想做好人了= =)明白了~
一下是高人话语~
void merge(int a,int b)
{
father[a]=b;
place[a]+=number[b];
number[b]+=number[a];
}
int Find(int a)//检查找和路径压缩
{
if(father[a]==-1)return a;
int tmp=father[a];
father[a]=Find(father[a]);
place[a]+=place[tmp];//你需要主要思考这一句话!
return father[a];
}
上面的代码是这一道题目的精华,标红字的需要你仔细体会,它确实使我想了好几天才明白。首先,在读了Union代码之后你会发现:当我们把一棵树接在另一棵树的上面时,只有根节点的place值变化了。在思考后,你将会惊讶地发现,其实每个点的place值都是与它父亲place值的相对值!当它的父亲路径压缩后直接接在“顶头上司”之下时,也就是说,当它的父亲完成路径压缩的递归时,它的place值将会是它原来与它父亲的相对值加上现在父亲与“顶头上司”的相对值,想明白这一点,你就无敌了!最后请注意:执行C命令时,输出place[a]之前不要忘了路径压缩哦,至于为什么,原理你明白……
这样的话给出我的代码
View Code
1 #include <iostream> 2 #include <stdio.h> 3 using namespace std; 4 int set[30005],r[30005],num[30005]; 5 int find(int x) 6 { 7 int temp; 8 temp = set[x]; 9 if(x != set[x]) 10 { 11 set[x] = find(set[x]); 12 r[x] += r[temp]; 13 } 14 15 return set[x]; 16 } 17 void merge(int x,int y) 18 { 19 x = find(x); 20 y = find(y); 21 if(x != y) 22 { 23 set[x] = y; 24 r[x] += num[y]; 25 num[y] += num[x]; 26 } 27 28 } 29 int main() 30 { 31 int t,i,x,y; 32 char order[5]; 33 scanf("%d",&t); 34 for(i = 1;i < 30005;i++) 35 set[i] = i,r[i] = 0,num[i] = 1; 36 while(t--) 37 { 38 scanf("%s %d",order,&x); 39 if(order[0] == 'M') 40 { 41 scanf("%d",&y); 42 merge(x,y); 43 } 44 else 45 { 46 find(x); 47 printf("%d\n",r[x]); 48 } 49 50 } 51 return 0; 52 }