可撤销并查集
用途
- 顾名思义, 可以将以前的 Merge 操作撤销
- 但是只能从后往前一步一步撤销, 做不到像主席树一样直接访问历史版本
- 多用于树上问题
原理
- 按秩合并
- 将集合 x 和 y 合并时, 如果 siz[x] > siz[y], 那么就把 y 的父亲设为 x, 反之亦然
- (和启发式合并有点像)时间复杂度
- 用栈维护操作序列
过程
| int s[N], si[N], cnt; |
| int st[N], tp; |
| int Find(int x){ |
| if(x != s[x]){ |
| return Find(s[x]); |
| } |
| return s[x]; |
| } |
| void Merge(int x, int y){ |
| int fa = Find(x); |
| int fb = Find(y); |
| if(fa == fb){ |
| return; |
| } |
| if(si[fa] < si[fb]){ |
| swap(fa, fb); |
| } |
| s[fb] = fa; |
| si[fa] += si[fb]; |
| st[++tp] = fb; |
| } |
| void Delete(int x){ |
| while(tp > x){ |
| int k = st[tp]; |
| si[s[k]] -= si[k]; |
| s[k] = k; |
| tp--; |
| } |
| } |
完整代码
| |
| struct Ufs{ |
| int s[N], si[N], cnt; |
| int st[N], tp; |
| |
| inline void Insert(){ |
| ++cnt; |
| s[cnt] = cnt; |
| si[cnt] = 1; |
| } |
| |
| int Find(int x){ |
| if(x != s[x]){ |
| return Find(s[x]); |
| } |
| return s[x]; |
| } |
| |
| void Merge(int x, int y){ |
| int fa = Find(x); |
| int fb = Find(y); |
| if(fa == fb){ |
| return; |
| } |
| if(si[fa] < si[fb]){ |
| swap(fa, fb); |
| } |
| s[fb] = fa; |
| si[fa] += si[fb]; |
| st[++tp] = fb; |
| } |
| |
| void Delete(int x){ |
| while(tp > x){ |
| int k = st[tp]; |
| si[s[k]] -= si[k]; |
| s[k] = k; |
| tp--; |
| } |
| } |
| }s; |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话