在了解带权并查集前,我们先要理清楚我们前面讲的并查集的路径压缩。
int find(x){
int p=x;
if(p!=pre[p])pre[p]=find(pre[p]);
return pre[p];
}
前面我们讲了,这一步操作能够使得find路径上的节点全部指向根节点。
对于一般的并查集来说,我们仅需要知道每个节点的父节点是谁,进而用find可以找到他的根节点。
对于带权并查集,我们要知道每个节点与他父亲之间的权值。(实际上这个权值是对关系的编码,用权重表示关系,具体后面结合题目来说) 进而用find可以找到他与根节点之间的权值(关系)。
我们知道pre[]数组是保存某个节点的父节点是谁。而加权并查集要一个value[]数组保存某个节点与他父节点之间的权值。而这个权值在其父节点改变时自然也会发生改变。
假设这里的权值表示距离,长度。
带权并查集路径压缩
int find(x){
int p=x;
if(p!=pre[p])
{
int t=pre[p];
pre[p]=find(pre[p]);
value[p]+=value[t];//随着权值表达的关系不同而变化。
}
return pre[p];
}
上面的代码是什么意思呢,因为有p->pre[p]->…->root,其中value[t]代表t到其父节点的距离。很明显路径压缩后value[t]代表的是t到根节点的距离,该值=t到父节点的距离+t父节点到根节点的距离,这是一个递归关系。假如value[t的父节点]已经更新为t的父节点到root的距离,则value[t]就可通过+value[t的父节点]得出。而上面这个函数就可发现在求value[t]时,value[t的父节点]已经更新。
带权并查集的合并
int px=find(x);
int py=find(y);
if(px!=py)
{
parent[px]=py;
value[px]=value[y]+s-value[x];//s为x到y距离,随着权值表达的关系不同而变化。
}
第二个公式是由于x通过不同道路到py距离相同。
s+value[y]=value[x]+value[px];
//s为x到y距离,value[y]经过find已经成为y到fy距离。value[x]表示x到fx距离,value[px]表示px到py距离。
//未完待续。
例题1:HDU-3038