[51Nod 1515] 明辨是非
Description
给\(n\)组操作,每组操作形式为\(x\;y\;p\)。
当\(p\)为\(1\)时,如果第\(x\)变量和第\(y\)个变量可以相等,则输出\(YES\),并限制他们相等;否则输出\(NO\),并忽略此次操作。
当\(p\)为\(0\)时,如果第\(x\)变量和第\(y\)个变量可以不相等,则输出\(YES\),并限制他们不相等 ;否则输出\(NO\),并忽略此次操作。
Input
输入一个数\(n\)表示操作的次数\((n<=10^5)\)
接下来\(n\)行每行三个数\(x\;y\;p\) \((x,y<=10^8,0≤p≤1)\)
Output
对于\(n\)行操作,分别输出\(n\)行\(YES\)或者\(NO\)
Solution
没想到假的启发式合并也能A题啊。。。
正解其实跟考试时候的思路差不多
但是不是维护每个联通块的大小
因为有可能一个联通块大小比较小但是连出去的边有很多
所以我们要换一种数据结构维护每个联通块连出去了多少条边
用什么数据结构可以维护大小,快速查找两个元素是否有关系呢?
嗯... \(STL\) 的 \(set\) 是符合要求的 查询大小是 \(O(1)\) 的,查找是 \(O(nlogn)\) 的
所以我们用一个 \(set\) \(s[i]\) 表示以 \(i\) 为根的联通块连出去的边(这里连边表示规定两个联通块严格不相等)
考虑操作
如果要求两个变量相等,那么就在两个联通块的 \(set\) 里找是否存在一条边连到了对方,如果有,那么此条件无法满足。
如果要求两个变量不相等,那么假设它们不在一个联通块里,需要合并这两个联通块,就要用到启发式合并了。
注意到我们已经记录了两个联通块连出去边的个数了, 为了保证复杂度,一定是想让连边少的联通块合并到连边多的联通块里。这就是启发式合并了。
Code
#include<set> #include<map> #include<cstdio> #define N 100005 int n,tot; int ques [5]; int father[N<<1]; std::map<int,int> mp; std::set<int> s[N<<1]; int find(int x){ if(father[x]==x) return x; return father[x]=find(father[x]); } signed main(){ scanf("%d",&n); for(int x,y,i=1;i<=n;i++){ scanf("%d%d%d",&x,&y,&ques[i][3]); if(!mp[x]) mp[x]=++tot; if(!mp[y]) mp[y]=++tot; ques[i][1]=mp[x]; ques[i][2]=mp[y]; } for(int i=1;i<=tot;i++) father[i]=i; for(int i=1;i<=n;i++){ int r1=find(ques[i][1]); int r2=find(ques[i][2]); if(ques[i][3]==1){ if(r1==r2) {puts("YES");continue;} if(s[r1].find(r2)!=s[r1].end() or s[r2].find(r1)!=s[r2].end()){ puts("NO"); continue; } if(s[r1].size()>s[r2].size()) r1^=r2^=r1^=r2; std::set<int>::iterator it; for(it=s[r1].begin();it!=s[r1].end();it++) s[r2].insert(*it),s[*it].insert(r2),s[*it].erase(r1); father[r1]=r2; puts("YES"); } else{ if(r1==r2) {puts("NO");continue;} if(s[r1].find(r2)!=s[r1].end() or s[r2].find(r1)!=s[r2].end()){ puts("YES"); continue; } s[r1].insert(r2); s[r2].insert(r1); puts("YES"); } } return 0; }
- 51nod 1515 明辨是非(合并并查集)
- 51Nod-1515-明辨是非
- 51nod 1515 明辨是非[Waiting]
- 【51nod 1515】 明辨是非
- 【51Nod 1515】明辨是非
- 51nod 1515 明辨是非 并查集 + set + 启发式合并
- 51nod 1515 明辨是非 && 2017百度之星初赛第一场第二题(并查集+启发式合并)
- 51nod 1515 明辨是非[并查集][set]
- 51nod 1515:明辨是非 并查集合并
- 51nod 1515:明辨是非 并查集合并
- 51nod 1515 明辨是非 启发式合并
- 51 nod 1515 明辨是非(并查集合并)
- 51nod 1103 n的倍数
- 51nod 1459 spfa floyd
- 51nod 1184 第N个质数
- 51nod 1058 N的阶乘的长度(斯特林公式)
- 51nod 1393 0和1相等串
- 51nod 1101 换零钱
- 51nod 1432 独木舟问题
- 【51NOD 1048】【51NOD 1383】整数分解为2的幂 V2