Mahmoud and a Dictionary

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\n";
55         else cout<<"NO\n";
56     }
57     while(q--){
58         string x,y;
59         cin>>x>>y;
60         cout<<query(mp[x],mp[y])<<"\n";
61     }
62 }

 

转载于:https://www.cnblogs.com/barrier/p/6380359.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值