并查集:
我们知道p[x]中存储的是x的根节点,或者说,我们要的目的是所有在一棵树上的节点,他们的p[x]必须是相同的
并查集的代码很简单,但在使用时很难达到上述结果,或者说,稍有不慎,就会出错。
也许你会说我只要判断find(i)==find(1)都成立就好了,但这往往只能判断一个连通集的问题。
所以具体的方法是什么?我们先描述方法,再证明。
步骤:
int find(int x)
{return x==p[x]?x:p[x]=find(p[x]);}
read(u,v);
f1=find(u);f2=find(v);
if(f1!=f2) p[f2]=f1;
for(i=1;i<=n;i++) find(i);//这是关键 = =!,坑我无数遍
证明:
举个反例即可:
2<->1
3<->4
2<->3
结果: x 1 2 3 4
p[x] 2 2 2 3
实际上,4接在3,而3已经接到2上了,所以最后一个循环的作用是保证只存在最多两层高的树,所有节点都连到根节点上,也就保证了一个连通分量内p[x]都相同。