并查集(带权和求集合总数)
基本操作
const int MAX=1e6+10;
int p[MAX];//集合序数
int r[MAX];//权
将n个序数变为n个集合集合名为他们自己的序数
void clear(int n){
for(int i=0;i<=n;i++){
p[i]=i;
r[i]=0;//这里地权值视情况而变
}
}
查找根节点
int find(int x) {
if (x != p[x]) {
int f = p[x];
p[x] = find(p[x]);
r[x] += r[f];//权值运算视情况而变化
}
return p[x];
}
将两个序数合并在一个集合里
void join(int x, int y){
int a=find(x), b=find(y);//a为x所在集合的根节点, b为y所在集合的根节点
p[a]=b;
}
奇怪的操作
1.将p的序数范围扩增至x倍, 即定义p时的下标范围是大于xn的。这样可以用a,a+n, a+2n…来将同个数之间的某种关系集合化,也可以是a和b+n和b有两种关系的集合化。(应该是叫拓展域吧,没理解,不会)
2.权值计算时%某个数,可以制造一定范围内的循环,从而使集合内的某些元素具有特定的关系。
最后姑姑保佑