搞了两年ACM,终于准备写一些博客了,总得留下点什么。
不了解并查集的话,推荐这个博客学习,讲的很有意思,当时笑出声。
下面写一下自己的理解吧
并查集最简单的用法,就是把不同的元素归并到一个集合里。
在集合里选出一个老大作为代表,集合里的其他元素都是他的小弟。这样,就可以判断任意两个元素是不是属于同一个集合,还可以计算一个图中有多少个连通块。
并查集支持删点操作
但并不是所有模型都能删点哦!如果点与点之间的关系是在同一集合或者不在同一集合这种关系,就可以删点。比如:A-B&&B-C,删掉点B,A和C还在同一集合。但是,如果点与点的关系是连通与不连通的关系,就不能删点了。比如 A-B&&B-C,删掉点B,A和C就不连通了。**总结就是,如果删完点后会影响其他点之间的关系,这样就不能删点**
那么如何删点呢
网上的叫法是建立“虚点”,意思就是用一个数组把元素指向一个值,用这个值来代替元素。如:
find(id[a]);//用id[a]来代替a。`
删除一个点的操作就是,把元素指向一个新的值,以前的值就丢弃了。
void delete(a){
id[a] = overloop++;//overloop大于n
}
怎么删除不能删的点和边呢
一般做法都是逆向处理询问,离线处理,删边换成加边,删点换成加点。
并查集的难点就是处理点与点之间的关系
像线段树一样,并查集与能在点上存放&处理数据。**并查集处理的是点与点之间的关系**
比如:*BZOJ 1015*
这题要求的是x所在的集合内是否存在value值大于value[x]的点。
在连通两个点的时候,选择value值较大的点为根即可。
void join(int x,int y){
int fx = Find(x);
int fy = Find(y);//找到双方的老大
if(fx!=fy){
if(value[fx]>value[fy])father[fy] = fx;
else father[fx] = fy //谁的老大更厉害就选谁。
}
}
*POJ 1984*
这里要求一个图中任意两个点的manhattan距离(这里简化一下问题,把manhattan距离改为平面距离,二维降到一维)。
要怎么求呢?
易知,任意两个点之间肯定有一个老大(根结点),那么记录每个点与根结点的距离,就可以求得两个点间的距离了。
但是,老大是会变的!要更新信息。
int Find(int x){
if(x!=father[x]){
int fa = Find(father[x]);
distance[x]+=distance[father[x]];//x点到根结点的距离就是x到x的父亲的距离加上x的父亲到根结点的距离。
father[x] = fa;
}
return father[x];
}
void join(int x,int y){
int fx = Find(x);
int fy = Find(y);
if(fx!=fy){
father[fy] = fx;
distance[fy] = distance[x]-distance[y] + len;//len是x与y的距离
}
}
感觉写的很差哈,写博客好费时间啊
还没写完,下次更新吧,争取用图来解释问题。