[复习] 种类并查集 & 2-XOR-SAT

[复习] 种类并查集

种类并查集也可叫做扩展域并查集。

前言

自从两年多前刚学并查集时过了食物链后,就再也没有写过种类并查集。
今天回顾一下。

例题 1 食物链

P2024 [NOI2001] 食物链

题目大意:有 n 个动物,每个动物属于 A,B,C 种中的一种,ABBCCA。每次给出 x,y 同类或 xy 的信息,看是否合法。

首先 x,y 同类可以想到用并查集维护。那么 xy 怎么维护呢。

xy 时,我们不能将 x,y 放到一个并查集里表示它们不同。否则如果 ab,bc,cd,那此时 a,d 其实是同类的。

考虑一个动物,我们并不需实际区分它是哪个类别,只需考虑它和其他动物的关系即可。

于是考虑并查集取出 3n 个点,1n 为第一类,n+12n 为第二类,2n+13n 为第三类。

我们这样表示它们的关系:

对于同一类中的点 (x,y),如果它们在同一个集合中,则 (x,y) 同类。
对于不在同一类中的点 (x+kn,y+kn),如果它们在同一个集合中,则 (x,y) 不同类。
第一类吃第二类,第二类吃第三类,第三类吃第一类。

于是缩点就变成了:

  • 如果 x,y 同类,那么 (x,y),(x+n,y+n),(x+2n,y+2n) 缩点。
  • 如果 xy,那么 (x,y+n),(x+n,y+2n),(x+2n,y) 缩点。

2-XOR-SAT

SAT 问题,是一个 NP 完全问题,求 n 个布尔变量,有若干条限制,每条限制形如给定若干布尔变量分别为 0/1,要至少有一个布尔变量满足。

  • 2-SAT 问题,每条限制由两个变量组成,可以用 SCC 缩点在 O(n+m) 解决。
  • XOR-SAT 问题,将 SAT 问题的限制改为用异或连接,每条限制要使最终异或值为 0/1,可以用高斯消元在 O(n3) 解决。
  • 2-XOR-SAT 问题,每条限制给定两个变量和它们的异或值,要求构造方案或判断无解。

2-XOR-SAT 问题可用本篇的种类并查集做。

还是 1n 表示第一类,n+12n 表示第二类,同类点缩在一起表示它们相等,不同类点缩在一起表示它们不等。

我们知道,异或值指示了两个布尔数是否相同。

于是显然有这样的缩点策略:

  • 如果 axay=1,那么缩点 (x,y+n),(x+n,y) 表示 (x,y) 不等。
  • 如果 axay=0,那么缩点 (x,y),(x+n,y+n) 表示 (x,y) 相等。

例题 2 arc183_c

arc183_c

题目大意:
n 个人,每个人是诚实或撒谎,清醒或糊涂。其中:
清醒的诚实人说真话。
清醒的撒谎人说假话。
糊涂的诚实人说假话。
糊涂的撒谎人说真话。
给定 m 个条件,形如 a,b[1,n],c=0/1,表示 a 号人说 b 号人是诚实或撒谎。

我们可以设布尔变量 pi0/1 表示 i 是诚实或是撒谎,qi0/1 表示 i 是清醒或是糊涂。

那么条件 (a,b,c) 就相当于要满足 paqapb=c

这是三元的,并不好,我们可以考虑设 ri=piqi,那么条件就变成了 rapb=c,我们可以求 ri,pi,然后用 qi=ripi 算出 qi

关于方案,如果最后合法了,那么对于缩在一起的点(包括不同类点),我们指定一个点随便取一个值后,就能全部确定这些点。

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;
}
posted @   dengchengyu  阅读(62)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示