算法竞赛备赛——【数据结构】并查集
并查集
普通并查集
注意根据数据大小来开int 或者 long long 否则容易MLE
树的存储结构 双亲表示法——数组 孩子表示法 孩子兄弟表示法
P3367 【模板】并查集 - 洛谷
#include <bits/stdc++.h>
using ll=long long;
using namespace std;
const int N=2e5+5;
int fa[N];
int n,m;
int find(int x){
if(x==fa[x])
return x;
else return fa[x]=find(fa[x]);
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;++i){
fa[i]=i;
}
for(int i=0;i<m;++i){
int z,x,y;cin>>z>>x>>y;
if(z==1){
//合并
int fx=find(x);
int fy=find(y);
fa[fx]=fy;
}else{
//查询
int fx=find(x);
int fy=find(y);
if(fx==fy) cout<<"Y"<<endl;
else cout<<"N"<<endl;
}
}
return 0;
}
种类并查集
扩展域并查集 可描述敌对关系
敌人 朋友 没关系 扩展为2n
天敌 同类 猎物 没关系 扩展为3n
[P1525 NOIP 2010 提高组] 关押罪犯 - 洛谷
#include <bits/stdc++.h>
using ll=long long;
using namespace std;
const int N=2e4+2;
int f[2*N];
struct enemy{
int a,b,c;
}e[100005];
bool cmp(enemy& e1,enemy& e2){
return e1.c>e2.c;
}
int find(int x){
if(f[x]==x){
return x;
}
else return f[x]=find(f[x]);
}
int main(){
int n,m;cin>>n>>m;
for(int i=1;i<=2*n;++i){
f[i]=i;
}
for(int i=1;i<=m;++i){
cin>>e[i].a>>e[i].b>>e[i].c;
}
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++){
int fa=find(e[i].a);
int fb=find(e[i].b);
int fad=find(e[i].a+n);
int fbd=find(e[i].b+n);
if(fa==fb){
cout<<e[i].c;
return 0;
}
f[fa]=fbd;
f[fb]=fad;
}
cout<<0<<endl;
return 0;
}
[P2024 NOI2001] 食物链 - 洛谷
#include <bits/stdc++.h>
using ll=long long;
using namespace std;
const int N=5e4+5;
int f[3*N];
int find(int x){
if(f[x]==x){
return x;
}
else return f[x]=find(f[x]);
}
int main(){
int n,k;cin>>n>>k;
int ans=0;
for(int i=1;i<=3*n;++i){
f[i]=i;
}
while(k--){
int m,x,y;
cin>>m>>x>>y;
if(x>n||y>n||(m==2&&x==y)){
ans++;
continue;
}
int fx=find(x);//x同类
int fy=find(y);//y同类
int xenemy=find(x+n);//x天敌
int yenemy=find(y+n);//y天敌
int xeat=find(x+2*n);//x猎物
int yeat=find(y+2*n);//y猎物
if(m==1){
if(xenemy==fy||yenemy==fx){
ans++;
}else{
f[fx]=fy;
f[xenemy]=yenemy;
f[xeat]=yeat;
}
}
if(m==2){
if(fx==fy||yeat==fx){
ans++;
}else{
f[fy]=xeat;
f[yeat]=xenemy;
f[yenemy]=fx;
}
}
}
cout<<ans;
return 0;
}