原题传送门
前置知识:并查集,不会的补了再来。
这道题只是在并查集的基础上多了一个操作而已。
这种操作,叫做反集(就先这么叫着)
题目里有一种关系是互为朋友,这很好理解,把互为朋友的两个点合并就可以了。
互为敌人怎么办?
用反集!
所谓反集,就是分别把x,y和它们对应的虚点连接起来。(虚点:a的虚点是a+n(点数))
因为一个人不可能和自己是敌人(至少这道题里不会),所以x永远不会和x+n连接起来,但如果x和y+n连接起来了,x和y就永远不会在一个并查集里了。
有了这个特性,最后检查的时候遍历一遍1-n,如果它是根节点就ans++,最后输出即可。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,fa[2001],x,y,sz[10001]; 4 char o; 5 void init() 6 { 7 for(int i=1;i<=2000;i++) 8 { 9 fa[i]=i; 10 sz[i]=1; 11 } 12 } 13 int get(int x) 14 { 15 if(fa[x]==x)return x; 16 int r=get(fa[x]); 17 fa[x]=r; 18 return r; 19 } 20 void merge(int x,int y) 21 { 22 int r1=get(x),r2=get(y); 23 if(r1==r2) 24 { 25 return; 26 } 27 fa[r1]=r2; 28 sz[r2]+=sz[r1]; 29 return; 30 } 31 int main() 32 { 33 cin>>n>>m; 34 init(); 35 for(int i=1;i<=m;i++) 36 { 37 cin>>o>>x>>y; 38 if(o=='F')merge(x,y); 39 else 40 { 41 merge(y+n,x); 42 merge(x+n,y); 43 } 44 } 45 int ans=0; 46 for(int i=1;i<=n;i++) 47 { 48 if(fa[i]==i)ans++; 49 } 50 cout<<ans<<endl; 51 return 0; 52 }