Mahmoud and a Dictionary
题目链接:http://codeforces.com/problemset/problem/766/D
并查集
这种涉及到元素的关系的题目自然就想到了并查集。
我们给每个元素设定两个属性值:pre(前驱结点)和rela(与前驱结点的关系),其中,
当rela=0时,表示当前结点x与其前驱结点a[x].pre是同义词;
当rela=1时,表示当前结点x与其前驱结点a[x].pre是反义词。
由于同义词的同义词是同义词,反义词的反义词是同义词,词与词之间的关系符合模2的运算,即
若x和y的关系是1(反义词),y和z的关系是1(反义词),那么x和z的关系就为(1+1)%2=0(同义词)
因此,若x和y有关(x和y在同一个集合),那么就可以根据x,y与它们各自的祖先的关系计算出x与y的关系:
x与y的关系=(a[x].rela+a[y].rela)%2.
也就可以判断关系是否错误了。
//Orz队友给出了另一种做法:令词i的反义词为i+n; 如果i和j是同义词,那么i+n和j必是反义词。
代码如下:
1 #include <cstdio> 2 #include <iostream> 3 #include <map> 4 #include <string> 5 #define N 100005 6 using namespace std; 7 map<string,int>mp; 8 struct node{ 9 int pre,rela; 10 }a[N]; 11 int n,m,q; 12 void init(){ 13 for(int i=0;i<n;++i){ 14 a[i].pre=i; 15 a[i].rela=0; 16 } 17 } 18 int Find(int x){ 19 if(a[x].pre==x)return x; 20 int p=a[x].pre; 21 a[x].pre=Find(p); 22 a[x].rela=(a[p].rela+a[x].rela)%2; 23 return a[x].pre; 24 } 25 bool Join(int x,int y,int t){ 26 int fx=Find(x),fy=Find(y); 27 if(fx==fy){ 28 return (a[x].rela+a[y].rela)%2==t; 29 }else{ 30 a[fx].pre=fy; 31 a[fx].rela=(t+a[x].rela+a[y].rela)%2; 32 return 1; 33 } 34 return 0; 35 } 36 int query(int x,int y){ 37 int fx=Find(x),fy=Find(y); 38 if(fx==fy)return (a[x].rela+a[y].rela)%2+1; 39 else return 3; 40 } 41 int main(void){ 42 cout.sync_with_stdio(false); 43 cin>>n>>m>>q; 44 for(int i=0;i<n;++i){ 45 string s; 46 cin>>s; 47 mp[s]=i; 48 } 49 init(); 50 while(m--){ 51 int t; 52 string x,y; 53 cin>>t>>x>>y; 54 if(Join(mp[x],mp[y],t-1))cout<<"YES "; 55 else cout<<"NO "; 56 } 57 while(q--){ 58 string x,y; 59 cin>>x>>y; 60 cout<<query(mp[x],mp[y])<<" "; 61 } 62 }