Loading

浅谈扩展域并查集之种类并查集

[NOIP2010 提高组] 关押罪犯

考虑用并查集维护两个监狱里面的情况。首先对于 \([1,n]\) 我们表示为 \(A\) 监狱里面的情况,对于 \([n+1,2n]\) 我们表示为 \(B\) 监狱里面的情况,首先这两个监狱里面的情况是镜像的,因为你不确定也不需要确定哪个人到底去了哪个监狱,所以存镜像的表示关系就好了。

那么就很显然了,我们贪心排好序后直接交叉合并,如果出现冲突就直接输出并跳出即可。

#include<bits/stdc++.h>
using namespace std;
inline int read(){
  int ans=0,f=1;char ch=getchar();
  while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}
  while(isdigit(ch)){ans=(ans<<3)+(ans<<1)+ch-48;ch=getchar();}
  return ans*f;
}
const int N=1e5+5;
int n,m;
int fa[N<<1];
int find(int x){
  if(fa[x]==x) return x;
  return fa[x]=find(fa[x]);
}
struct lzk{
  int u,v,c;
}node[N];
bool cmp(lzk x,lzk y){
  return x.c>y.c;
}
int main(){
  n=read(),m=read();
  for(int i=1;i<=n<<1;i++) fa[i]=i;
  for(int i=1;i<=m;i++) node[i].u=read(),node[i].v=read(),node[i].c=read();
  sort(node+1,node+1+m,cmp);
  for(int i=1;i<=m;i++){
    int x1=find(node[i].u),y1=find(node[i].v);
    int x2=find(node[i].u+n),y2=find(node[i].v+n);
    if(x1==y1||x2==y2) return printf("%d",node[i].c),0;
    fa[x1]=y2;
    fa[x2]=y1;
  }
  printf("0");
  return 0;
}

[NOI2001] 食物链

这题也可以用到种类并查集,我们只需要开 \(3\) 倍的空间,\([1,n]\) 表示 \(A\) 类,\([n+1,2n]\) 表示 \(B\) 类,\([2n+1,3n]\) 表示 \(C\) 类。同样这也满足镜像的性质(也许是种类并查集的性质?),所以我们只用讨论一种即可。

  • 对于操作 \(1\),我们只用把同类的 \(x,y\) 合并就好了,如果出现 \(x,y\) 不同类的属于同一个集合,那么就意味着 \(x,y\) 有捕食关系就是假话;
  • 对于操作 \(2\),我们根据题目所给的 \(A\)\(B\)\(B\)\(C\)\(C\)\(A\) 的顺序合并即可,如果出现 \(x,y\) 属于同一类的同一个集合或者 \(y\)\(x\) 的情况,就是假话。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
  int ans=0,f=1;char ch=getchar();
  while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}
  while(isdigit(ch)){ans=(ans<<3)+(ans<<1)+ch-48;ch=getchar();}
  return ans*f;
}
const int N=1e5+5;
int n,m;
int cnt;
int fa[N*3];
int find(int x){
  if(fa[x]==x) return x;
  return fa[x]=find(fa[x]);
}
int main(){
  n=read(),m=read();
  for(int i=1;i<=n*3;i++) fa[i]=i;
  for(int i=1;i<=m;i++){
    int opt=read(),x=read(),y=read();
    if(x>n||y>n){cnt++;continue;}
    if(opt==1){
      int x1=find(x),y1=find(y);
      int x2=find(x+n),y2=find(y+n);
      int x3=find(x+(n<<1)),y3=find(y+(n<<1));
      if(x1==y2||x1==y3){cnt++;continue;}
      fa[x1]=y1;
      fa[x2]=y2;
      fa[x3]=y3;
    }
    else{
      int x1=find(x),y1=find(y);
      int x2=find(x+n),y2=find(y+n);
      int x3=find(x+(n<<1)),y3=find(y+(n<<1));
      if(x1==y1||x2==y1){cnt++;continue;}
      fa[x1]=y2;
      fa[x2]=y3;
      fa[x3]=y1;
    }
  }
  printf("%d",cnt);
  return 0;
}
posted @ 2021-02-19 17:03  Quick_Kk  阅读(63)  评论(2编辑  收藏  举报