模板
并查集
const int maxn=100010;
int f[maxn];
void init(){
for(int i=1;i<=n;i++) f[i]=i;
}
int find(int x){
if(x==f[x]) return x;
return f[x]=find(f[x]);
}
void join(int x,int y){
int fx=find(x);
int fy=find(y);
if(fx!=fy) f[fx]=fy;
}
种类并查集
种类并查集维护一种循环对称的关系,通常要有多个集合
带权并查集
带权并查集维护多个元素之间的连通关系以及偏移关系,偏移可以为当前节点到根节点的边长之和
const int maxn=200010,maxm=40010;
int f[maxn],sum[maxn];
void init(){
for(int i=1;i<=n;i++){
f[i]=i;
sum[i]=0;
}
}
int find(int x){
if(f[x]!=x){
int t=f[x];
f[x]=find(f[x]);
sum[x]+=sum[t];
}
return f[x];
}
void join(int x,int y,int s){
int fx=find(x);
int fy=find(y);
if(fx!=fy){
f[fx]=fy;
sum[fx]=-sum[x]+s+sum[y];
}
}
模板题:hdu3038 How Many Answers Are Wrong
#include<bits/stdc++.h>
#define LL long long
#define PII pair<int,int>
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
using namespace std;
const int maxn=200010,maxm=40010;
int n,m,f[maxn],sum[maxn];
void init(){
for(int i=0;i<=n;i++){
f[i]=i;
sum[i]=0;
}
}
int find(int x){
if(f[x]!=x){
int t=f[x];
f[x]=find(f[x]);
sum[x]+=sum[t];
}
return f[x];
}
void join(int x,int y,int s){
int fx=find(x);
int fy=find(y);
if(fx!=fy){
f[fx]=fy;
sum[fx]=-sum[x]+s+sum[y];
}
}
int main(){
while(scanf("%d %d",&n,&m)!=EOF){
init();
int ans=0;
for(int i=1;i<=m;i++){
int a,b,s;
scanf("%d %d %d",&a,&b,&s);
a--;
if(find(a)==find(b)){
if(sum[a]-sum[b]!=s) ans++;
}
else{
join(a,b,s);
}
}
printf("%d\n",ans);
}
}