当前位置: 首页 > news >正文

一类并查集维护的区间染色问题

并查集的区间染色

并查集作为一种高级数据结构,可以高效地维护元素与元素,元素与集合之间的关系。

在一些涉及到区间染色的题中,并查集可以很好地维护块的大小,块的边界和块的合并。

以例题来做具体解释。

[CF356A Knight Toumament](Problem - A - Codeforces)

题意

\(n\) 个骑士编号从 \(1\)\(n\),给出 \(m\) 场决斗。每场决斗给出 \(l , r, x\) 表示区间 \([l,r]\) 之间还没被打败的骑士之间进行决斗,编号为 \(x\) 的骑士获得胜利。数据保证最后只有一个骑士获得胜利,对于每个骑士,输出打败他的骑士的编号,特别的,最后胜利的骑士输出 \(0\)

  • \(2 \le n \le 3 \cdot 10^5\)
  • \(1 \le m \le 3\cdot 10^5\)

思路

这道题的关键在于快速找出 \([l,r]\) 之间还在场上的骑士。

对于每个被打败的骑士,向右边连一条边,遍历时只会在没有被打败的骑士处停下来。这里使用并查集加上路径压缩就能取得很优秀的复杂度。

要找到下一个骑士只需要继续遍历右边的一块就行,这里会把胜利的骑士也一同处理了,所以在最后把胜利的骑士的父亲再设置为自己就行了。

复杂度大约为 \(O(\alpha n)\)

具体思路在代码中有讲解。

代码

#include <bits/stdc++.h>using namespace std;const int N = 3e5+50;
int n,m,l,r,x,f[N],ans[N];
inline int Find(int x)
{if(f[x]!=x)f[x]=Find(f[x]);return f[x];
}int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=1;i<=n+1;i++)f[i]=i;while(m--){cin>>l>>r>>x;int now=Find(l);  //找到第一个仍在场上的骑士while(now<=r)     //超出范围就停止{ans[now]=x;   //被 x 打败f[now]=now+1; //向右连边now=Find(now);//找下一个,这里要注意只能从 now 和后面的位置开始找}                 //如果当前为 x 的话从左边找会破坏路径,直接跳过 xf[x]=x; }for(int i=1;i<=n;i++)cout<<(i==ans[i]?0:ans[i])<<' ';cout<<'\n';return 0;
}

ABC380E 1D Bucket Tool

题意

\(n\) 个格子排成一行,初始时第 \(i\) 个格子的颜色为 \(i\)。有 \(q\) 次操作,操作 \(1\) 给出 \(x,c\),将格子 \(x\) 与和 \(x\) 同色的色块染成 \(c\)。操作 \(2\) 给出 \(x\),询问颜色为 \(x\) 的格子的数量。

  • \(1\le n \le 5 \cdot 10^5\)
  • \(1\le q \le 2 \cdot 10^5\)

思路

考虑用并查集怎么做。

如果当前块右边的一块的颜色与当前块相同,就把当前块的父亲设置为右边的一块。这样每次遍历停下的点就是该极色块的右端点。

对于操作 \(1\) ,先要找到最大的一块,因为可能左右两块颜色相同但是并未相连,由于每次是在右端点停,对于右边一块直接找右端点的右边一个就行,这里还要维护左端点这个信息来向左扩展。

合并两个块时,左边的块的父亲设置为右边的块,更新大小和左边界。

直到无法扩展再更新颜色,这里要记录每种颜色的块原本有多少个,然后直接加减就行。

对于操作 \(2\),直接输出记录的数量就行。

代码

#include <bits/stdc++.h>using namespace std;const int N = 5e5+50;
int n,q,c[N],f[N],siz[N],cnt[N],L[N];
inline int Find(int x)
{if(f[x]!=x)f[x]=Find(f[x]);return f[x];
}int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>q;for(int i=1;i<=n;i++)c[i]=i,f[i]=i,siz[i]=1,L[i]=i,cnt[i]=1;while(q--){int op;cin>>op;if(op==1){int x,C;cin>>x>>C;int rt=Find(x);while(c[rt]==c[Find(L[rt]-1)])   //向左扩展{int to=Find(L[rt]-1);f[to]=rt;                      //左边合并到右边siz[rt]+=siz[to];L[rt]=L[to];} while(c[rt]==c[Find(rt+1)])     //向右扩展{int to=Find(rt+1);f[rt]=to;siz[to]+=siz[rt];L[to]=L[rt];rt=to;}cnt[c[rt]]-=siz[rt];            // 最后更新每种颜色的小块的数量cnt[C]+=siz[rt];c[rt]=C;}else{int x;cin>>x;cout<<cnt[x]<<'\n';}}return 0;
}

小结

对于区间染色,并查集做到的实际上是快速跳过已经被合并的元素来降低复杂度,对于一些区间能够合并或者是元素会被消除的题,不妨考虑一下能否使用并查集。

http://www.jsqmd.com/news/461732/

相关文章:

  • 替代WSTCC1130T双节锂电池充电IC集成均衡充功能
  • Win11操作系统激活
  • PPT Timer:一个置顶于PPT全屏放映之上的LCD倒计时器
  • AI赛博飞升,我们离“仙界”还远么
  • OpenClaw 完整安装指南
  • windows通过wsl的方式安装ubuntu系统(含离线方式)
  • (windows)本地安装openclaw,完成配置并接入本地大模型(ollama)全流程指南
  • 浏览器自动将http访问链接自动转化为https链接,解决办法
  • c++ static关键字的详细用法和作用
  • Spring的IOC详解
  • 2026年苏州青少年篮球培训怎么选?这几家TOP机构值得关注!
  • Claude Code 隐藏功能大全:90%的人不知道这些
  • 150 万人被偷家之后,我翻了翻自己的 API Key 管理,冷汗直流
  • 帮朋友拆了一个机械臂问题,从误解到最优解
  • FFMPEG网络推流
  • 技术落地解析:深圳市兴通物联俄罗斯诚信标签条码比对系统,提升对俄出口合规效率
  • 2026年叔丁醇钾选购,江苏天泽新材料费用合理值得考虑 - myqiye
  • 跑步耳机挂脖好还是无线好?2026最适合跑步用的耳机真实体验分享
  • Python保护类内部私有变量,不允许外部类访问的一种简单实现
  • 口碑好的多肽修饰厂家2026年排行榜,哪家服务更贴心 - 工业推荐榜
  • OpenClaw本地私有化部署教程
  • 进口阀门市场发展趋势与工业应用解析
  • 矩阵论考题——答案
  • 和信通卡回收折扣对比2026,畅回收平台折脱颖而出 - 畅回收小程序
  • PbootCMS附件上传报错UNKNOW: Code: 8192; Desc: stripos()
  • 收藏!小白程序员必看:手把手教你玩转大模型上下文工程,提升代理智能
  • 亚马逊合规趋严,海外仓如何破解物流卡点,实现高效履约?
  • 2026年金华地区好用的日语高考培训学校排名 - mypinpai
  • docker安装nacos
  • 【金蝶云星空】如何给科目挂上核算维度