带权并查集种类并查集

时间:2023-02-07 12:57:23


 带权并查集种类并查集

例题:​​种类并查集 洛谷 P2024 食物链​​


与普通并查集不同是新增加属性:

group[i]:group[i]表示它和fa[i]的关系,对于这三种种类,同类可以用0表示,其他两种分别用1表示该结点被父节点吃,2表示该节点吃父节点。 

举个例子:现在有pa[3] = 4; group[3] = 1; 这里的group3]仅仅代表3和4属于属于不同的集团!!!!!(非常重要)

操作:

1.Find函数:

每次find的时候更新它属于哪个num,因为他之前的父亲的父亲已经是根节点了,所以可以利用它之前的父亲和它和之前父亲的关系更新它和根节点的关系,当然更新后的num还是和父亲的关系;不过父亲已经变成了根节点了;

find的代码:

 

int find(int x) {

if(pa[x]== x) return x;

int fa =find(pa[x]);

group[x]= (group[x] + group[pa[x]]) % 3;

returnpa[x] = fa;

}


2.unios_set函数: 
当然这个也要看题,不过大同小异; 
代码中的变量解释: 
fx: x的根节点,fy:y的根节点;

group[x]: x和它父亲的关系(重要)

type:指传入的x和y是什么关系, 1代表他们是同类, 2代表x吃y(和例题目中是一样的);

pa[x]代表x的父亲;

 

代码解释:

 

if(fx ==fy) 表示他们属于同一个集合,因为x和y已经find过了,所以他们的group都是和根节点的关系(当然他们的根节点是一样的因为fx = fy)这个时候只需要看满不满足type就OK了;

 

如果他们不是同一个集合,就链接两个集合;

 

如果你不是很熟悉,可以把所有的情况的考虑一下;

这里提一下, group[fx] = grou[fy] = 0; 因为他们没有父亲,而我们初始化的时候都初始化成0的;

比如y和x是同一个group 1.type == 1 那么fx和fy同一类;group[fx] 不变为 0;

2.type ==2 因为我们会更新pa[fx]= fy; type == 2 说明x吃y本来x和y的group是一样的,所以只要把x的group+1就OK了,因为x的group加了1,所以该集合中的所有元素的group必定也+1(他们是一体的)所以不必更新group[x] 只需要更新group[fx] += 1(因为它的group = 0, 所以直接等于1页可以)就OK了,这样就实现了该集合的所有元素的group都更新了(因为在find函数的时候会更新group)

你可以再考虑一下group[y] - grou[x] = 1 后者2 或者-1 或者-2;就会发现他们可以用一个式子满足group[fx]= (group[y] - group[x] + 3 + (type - 1)) % 3;

 

union_set函数的代码:

boolunion_set(int type, int x, int y) {

int fx =find(x);

int fy =find(y);

if(fx ==fy) {

if(type== 1 && group[x] != group[y]) return true;

if(type== 2 && (group[y] + 1) % 3 != group[x]) return true;

returnfalse;

}

group[fx]= (group[y] - group[x] + 3 + (type - 1)) % 3;

pa[fx] =fy;

returnfalse;

}