并查集 Union Find / Disjoint Set Union
路径压缩和按 size 合并 Union by Size
// M: max number of set
// id is in [0~M-1]
template<size_t M>
struct UF {
int uf[M],sz[M];
int n;
int ns; // number of set
void init(int n_) {
n=ns=n_;
for(int i=0;i<n;i++) uf[i]=i,sz[i]=1;
}
int find(int x) { return x==uf[x]?x:uf[x]=find(uf[x]); }
bool same(int x,int y) { return find(x)==find(y); }
bool merge(int x,int y) {
x=find(x); y=find(y);
if(x==y) return false;
if(sz[x]>sz[y]) swap(x,y);
sz[y]+=sz[x]; uf[x]=y; ns--;
return true;
}
};
Debug:
void show() {
cerr<<"UnionFind:----------------------\n";
cerr<<"id:";
for(int i=0;i<n;i++) cerr<<'\t'<<i;
cerr<<'\n';
cerr<<"uf:";
for(int i=0;i<n;i++) cerr<<'\t'<<uf[i];
cerr<<'\n';
cerr<<"sz:";
for(int i=0;i<n;i++) cerr<<'\t'<<sz[i];
cerr<<'\n';
cerr<<"UnionFind:----------------------\n";
}
路径压缩按size合并和集合额外信息
// T must define +
// M: max number of set
// id is in [0~M-1]
template<typename T, size_t M, typename Op=plus<T>>
struct UF
{
static Op op;
int uf[M],sz[M];
T info[M];
int n;
void init(int n_,T info_[]) {
n=n_;
for(int i=0;i<n;i++) uf[i]=i,sz[i]=1;
for(int i=0;i<n;i++) info[i]=info_[i];
}
int find(int x) { return x==uf[x]?x:uf[x]=find(uf[x]); }
bool merge(int x,int y)
x=find(x); y=find(y);
if(x==y) return false;
if(sz[x]>sz[y]) swap(x,y);
sz[y]+=sz[x]; uf[x]=y;
info[y]=op(info[x],info[y]);
return true;
}
bool same(int x,int y) { return find(x)==find(y); }
// get the info of the set contained x
T& getinfo(int x) { return info[find(x)]; }
};
Debug:
void show() {
cout<<"UnionFind:----------------------\n";
cout<<"id:";
for(int i=0;i<n;i++) cout<<'\t'<<i;
cout<<'\n';
cout<<"uf:";
for(int i=0;i<n;i++) cout<<'\t'<<uf[i];
cout<<'\n';
cout<<"info:"
for(int i=0;i<n;i++) cout<<'\t'<<info[i];
cout<<'\n';
cout<<"UnionFind:----------------------\n";
}
按 size 合并及回滚 Rollback
回滚部分未测试
// M: max number of set
// id is in [0~M-1]
template<size_t M>
struct UF
{
typedef pair<int,int> PII;
int uf[M],sz[M];
int n;
stack<PII> st;
void init(int n_)
{
n=n_;
while(!st.empty()) st.pop();
for(int i=0;i<n;i++) uf[i]=i,sz[i]=1;
}
int find(int x)
{
return x==uf[x]?x:find(uf[x]);
}
bool merge(int x,int y)
{
x=find(x); y=find(y);
if(x==y)
return st.emplace(-1,-1),false;
if(sz[x]>sz[y]) swap(x,y);
sz[y]+=sz[x]; uf[x]=y; st.emplace(x,y); // x->y
return true;
}
bool rollback() // check st.empty()
{
PII p=st.top(); st.pop();
int x=p.first,y=p.second;
if(x==-1) return false;
sz[y]-=sz[x]; uf[x]=x;
return true;
}
};
Debug:
void show()
{
cout<<"UnionFind:----------------------\n";
cout<<"id:";
for(int i=0;i<n;i++) cout<<'\t'<<i;
cout<<'\n';
cout<<"uf:";
for(int i=0;i<n;i++) cout<<'\t'<<uf[i];
cout<<'\n';
cout<<"UnionFind:----------------------\n";
}
路径压缩和按秩合并 Union by Rank
// M: max number of set
// id is in [0~M-1]
template<size_t M>
struct UF
{
int uf[M],rk[M];
int n;
void init(int n_)
{
n=n_;
for(int i=0;i<n;i++) uf[i]=i,rk[i]=0;
}
int find(int x)
{
return x==uf[x]?x:uf[x]=find(uf[x]);
}
bool merge(int x,int y)
{
x=find(x); y=find(y);
if(x==y) return false;
if(rk[x]<rk[y]) uf[x]=y;
else if(rk[x]>rk[y]) uf[y]=x;
else uf[y]=x,rk[x]++;
return true;
}
};
Debug:
void show()
{
cout<<"UnionFind:----------------------\n";
cout<<"id:";
for(int i=0;i<n;i++) cout<<'\t'<<i;
cout<<'\n';
cout<<"uf:";
for(int i=0;i<n;i++) cout<<'\t'<<uf[i];
cout<<'\n';
cout<<"rk:";
for(int i=0;i<n;i++) cout<<'\t'<<rk[i];
cout<<'\n';
cout<<"UnionFind:----------------------\n";
}
路径压缩 Path Compression
// M: max number of set
// id is in [0~M-1]
template<size_t M>
struct UF
{
int uf[M];
int n;
void init(int n_)
{
n=n_;
for(int i=0;i<n;i++) uf[i]=i;
}
int find(int x)
{
return x==uf[x]?x:uf[x]=find(uf[x]);
}
bool merge(int x,int y)
{
x=find(x); y=find(y);
if(x==y) return false;
uf[x]=y;
return true;
}
};
Debug:
void show()
{
cout<<"UnionFind:----------------------\n";
cout<<"id:";
for(int i=0;i<n;i++) cout<<'\t'<<i;
cout<<'\n';
cout<<"uf:";
for(int i=0;i<n;i++) cout<<'\t'<<uf[i];
cout<<'\n';
cout<<"UnionFind:----------------------\n";
}
测试
全部测试未开 O2 优化,感觉 P3367 数据量不是特别够,所以结果也不是很有参考价值
题目 | 写法 | 时间(ms) |
---|---|---|
Luogu P3367 【模板】并查集 | 路径压缩 | 240 |
Luogu P3367 | 按秩合并 | 275 |
Luogu P3367 | 路径压缩按秩合并 | 249 |
Luogu P3367 | 按 size 合并 | 288 |
Luogu P3367 | 路径压缩按 size 合并 | 223 |
Next: [模板][图论] 弗洛伊德 Floyd