一般的并查集是维护属于同一种类的元素,对于属于不同种类的元素之间的关系没有记录。种类并查集就是同一集合中的元素是已经确定关系的(是否属于同一种类),然后加一个group数组,记录一下孩子和父亲是否属于同一种类,递推稍稍改一下就可以了。
poj1703:http://poj.org/problem?id=1703
题目大意:有n个罪犯,两个帮派,已知其中若干对两者属于不同帮派,求给定的罪犯是否属于同一帮派。
需要注意,给的两个罪犯可能已经在同一个集合里了,需要处理一下,不然就无限递归了。。。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 const int maxn=1e5+5; 6 int p[maxn],group[maxn],n,m; 7 int Find(int x){ 8 if(p[x]==x)return x; 9 int t=Find(p[x]); 10 group[x]=group[x]==group[p[x]]?1:0; 11 return p[x]=t; 12 } 13 void Unit(int a,int b){ 14 int x=Find(a),y=Find(b); 15 if(x==y)return; 16 p[x]=b; 17 group[x]=1^group[a]; 18 } 19 int Is_same(int a,int b){ 20 int x=Find(a),y=Find(b); 21 if(x!=y)return -1; 22 return group[a]==group[b]; 23 } 24 int main(){ 25 int t,a,b; 26 char c; 27 scanf("%d",&t); 28 while(t--){ 29 scanf(" %d%d",&n,&m); 30 for(int i=0;i<n;i++){p[i]=i;group[i]=1;} 31 for(int i=0;i<m;i++){ 32 scanf(" %c%d%d",&c,&a,&b); 33 a--;b--; 34 if(c=='D'){ 35 Unit(a,b); 36 }else{ 37 int t=Is_same(a,b); 38 if(t==-1)printf("Not sure yet. "); 39 else if(t==0)printf("In different gangs. "); 40 else if(t==1)printf("In the same gang. "); 41 } 42 } 43 } 44 return 0; 45 }
51nod 1204 Parity
分析:记前k个的和的奇偶性为f[k],若[a,b]和为偶数,则f[a]==f[b],否则f[a]!=f[b],然后用种类并查集维护一下就可以了。
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 const int maxn=100005; 5 int p[maxn],group[maxn],n,q; 6 int Find(int x){ 7 if(p[x]==x)return x; 8 Find(p[x]); 9 group[x]=group[p[x]]==group[x]?1:0; 10 p[x]=Find(p[x]); 11 return p[x]; 12 } 13 int main(){ 14 cin>>n>>q; 15 for(int i=0;i<=n;i++){p[i]=i;group[i]=1;} 16 int a,b,ans=-1; 17 char s[10]; 18 for(int i=0;i<q;i++){ 19 cin>>a>>b>>s; 20 int x=Find(a-1),y=Find(b); 21 if(s[0]=='e'){ 22 if(x==y&&group[a-1]!=group[b]&&ans==-1) 23 ans=i+1; 24 if(x!=y){ 25 p[x]=y; 26 group[x]=group[a-1]==group[b]?1:0; 27 } 28 }else{ 29 if(x==y&&group[a-1]==group[b]&&ans==-1) 30 ans=i+1; 31 if(x!=y){ 32 p[x]=y; 33 group[x]=group[a-1]==group[b]?0:1; 34 } 35 } 36 } 37 cout<<ans<<endl; 38 return 0; 39 }