普通并查集
一般地运用并查集可以简单的判断连通性,以及可以用来解决最短路问题。普通的并查集有路径压缩和按秩合并两种优化的方法。路径压缩的并查集写法如下
int Getp(int a){
if(a!=f[a]) f[a]=Getp(f[a]);
return f[a];
}
void join(int a,int b){
int fa = Getp(a);
int fb = Getp(b);
if(fa!=fb) f[fa]=fb;
}
带权并查集
带权并查集可以理解为就是向量之间的关系。
如果要合并A和B则要注意的是两个向量的加。
写法以食物链为例
int Getp(int x)//找寻父节点+路径压缩
{
if(x==f[x]) return f[x];
int y=Getp(f[x]);
deep[x]=(deep[x]+deep[f[x]])%3;
return f[x]=y;
}
int join(int typ,int x,int y)
{
int fx=Getp(x);
int fy=Getp(y);
if(fx==fy)//共父节点才能判断出关系
{
if((deep[x]-deep[y]+3)%3==typ-1)
return 0;
return 1;
}
f[fx]=fy;
deep[fx]=(-deep[x]+typ-1+deep[y]+3)%3;
return 0;
}
带撤销并查集
下面就谈到按秩合并的写法了。某些情况下时必须要运用按秩合并的方法的,虽然路径压缩卸起来更为方便。 按秩合并主要是能解决一类带撤销的问题。
void Back(int tag) { //撤销到tag的位置
for (; cnt!= tag; Cnt --) { //cnt代表当前
if (que[cnt] < 0) deep[-que[cnt]] --;
else {
fa[que[cnt]] = que[cnt];
val[que[cnt]] = 0;
}
}
}
void Push(int u, int v, int val) { //合并u,v
if (deep[u] > deep[v]) swap(u, v);
if (deep[u] == deep[v]) {
deep[v] ++;
que[++ cnt] = -v;
}
fa[u] = v, val[u] = val;
que[++ cnt] = u;
}