浅谈并查集
普通并查集
就是开一个 数组表示 的祖先节点。
初始化
for(int i=1;i<=n;i++)fa[i]=i,siz[i]=1;
//fa[i]初始状态一定是只像自己的,siz[i]:表示 以 i 为根的子树大小
查询
inline int getf(int x)
{
if(x==fa[x])return x;
return getf(fa[x]);
}
合并
inline void merge(int u,int v)
{
u=getf(u),v=getf(v);
if(u!=v)
{
fa[u]=v;
}
}
优化
路径压缩
这个优化在查询中,就是在返回自己最高级祖先时,顺便更新自己的值。
inline int getf(int x)
{
if(x==fa[x])return x;
return fa[x]=getf(fa[x]);//就是这里
}
按秩合并
虽然在merge(u,v)
中,但是优化的是查询,原理是子树小的接子树大的(这也是树上启发式合并的雏形)。
inline void merge(int u,int v)
{
u=getf(u),v=getf(v);
if(u!=v)
{
if(siz[u]<siz[v])swap(u,v);
f[v]=u,siz[u]+=siz[v];//v小u大
}
}
扩展域并查集
根据名字,扩展域并查集的含义就是将领域扩展。
比如说扩展至 ,那么可以用 表示本身, 表示敌人(比如说 的敌人就是 ),非常好理解。
带权并查集
就是在合并时带上路径的权值。
il int getf(int x)
{
if(x==fa[x])return x;
int p=getf(fa[x]);//要确保祖先已经更新
top[x]+=top[fa[x]];
return fa[x]=p;
}
NOI2002 银河英雄传说
就是直接维护每一个队列所在的集合(普通并查集),再维护每个点到队顶的距离,每个队列的元素个数。
可撤销并查集
根据名字,可撤销并查集的含义就是能够撤销的并查集(但是只能按照加入的时间先后顺序撤销)。
直接上代码讲解:
int n,fa[N],siz[N],st[N],top=0;
il void getf(int x)
{
if(x==fa[x])return x;
return getf(fa[x]);
//由于后面需要支持撤销,故这里不因使用路径压缩,fa[i]数组只记录i的一级祖先
}
il void merge(int u,int v)
{
u=getf(u),v=getf(v);
if(u!=v)
{
if(siz[u]<siz[v])swap(u,v);
fa[v]=u,siz[u]+=siz[v];
}
}
il void upd()///删除上一条加入的边
{
if(top==0)return;
int x=s[top--];
siz[fa[x]]-=siz[x],fa[x]=x;
//将 x 从他父亲底下扯下去(删除 x 到 fa[x] 这条边更新siz,fa数组)
}
可持久化并查集
因该是个好东西,可惜我只会可持久化线段树Q_Q
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!