[复习] 种类并查集 & 2-XOR-SAT
[复习] 种类并查集
种类并查集也可叫做扩展域并查集。
前言
自从两年多前刚学并查集时过了食物链后,就再也没有写过种类并查集。
今天回顾一下。
例题 1 食物链
题目大意:有
首先
当
考虑一个动物,我们并不需实际区分它是哪个类别,只需考虑它和其他动物的关系即可。
于是考虑并查集取出
我们这样表示它们的关系:
对于同一类中的点
对于不在同一类中的点
第一类吃第二类,第二类吃第三类,第三类吃第一类。
于是缩点就变成了:
- 如果
同类,那么 缩点。 - 如果
,那么 缩点。
2-XOR-SAT
SAT 问题,是一个 NP 完全问题,求
- 2-SAT 问题,每条限制由两个变量组成,可以用 SCC 缩点在
解决。 - XOR-SAT 问题,将 SAT 问题的限制改为用异或连接,每条限制要使最终异或值为
,可以用高斯消元在 解决。 - 2-XOR-SAT 问题,每条限制给定两个变量和它们的异或值,要求构造方案或判断无解。
2-XOR-SAT 问题可用本篇的种类并查集做。
还是
我们知道,异或值指示了两个布尔数是否相同。
于是显然有这样的缩点策略:
- 如果
,那么缩点 表示 不等。 - 如果
,那么缩点 表示 相等。
例题 2 arc183_c
题目大意:
有
清醒的诚实人说真话。
清醒的撒谎人说假话。
糊涂的诚实人说假话。
糊涂的撒谎人说真话。
给定
我们可以设布尔变量
那么条件
这是三元的,并不好,我们可以考虑设
关于方案,如果最后合法了,那么对于缩在一起的点(包括不同类点),我们指定一个点随便取一个值后,就能全部确定这些点。
AC 代码:
const int N=2e5+5; int n,m; int fa[N*4]; int getfa(int x){ if(fa[x]==x)return x; return fa[x]=getfa(fa[x]); } void merge(int x,int y){ if(getfa(x)!=getfa(y)) fa[getfa(x)]=getfa(y); } int nx(int x){ if(x<=2*n)return x+2*n; return x-2*n; } int r(int x){ return x; } int p(int x){ return x+n; } void no(){ write("-1"); exit(0); } vector<int> t[N*4]; int ans[N*4],vis[N*4]; signed main(){ read(n,m); fo(i,1,n*4)fa[i]=i; fo(i,1,m){ int a,b,c; read(a,b,c); if(c){ if(getfa(r(a))==getfa(p(b))){ no(); } merge(r(a),nx(p(b))); merge(nx(r(a)),p(b)); } else{ if(getfa(r(a))==getfa(nx(p(b)))){ no(); } merge(r(a),p(b)); merge(nx(r(a)),nx(p(b))); } } fo(i,1,n*2)if(getfa(i)==getfa(nx(i)))no(); fo(i,1,n*4)t[getfa(i)].push_back(i); fo(i,1,n*4){ for(auto j:t[i]){ if(j<=2*n&&!vis[j]){ vis[j]=1; ans[j]=0; } else if(j>2*n&&!vis[j-2*n]){ vis[j-2*n]=1; ans[j-2*n]=1; } } } fo(i,1,n)write(ans[i]^ans[i+n]); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】