题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1515
给n组操作,每组操作形式为x y p。
当p为1时,如果第x变量和第y个变量可以相等,则输出YES,并限制他们相等;否则输出NO,并忽略此次操作。
当p为0时,如果第x变量和第y个变量可以不相等,则输出YES,并限制他们不相等 ;否则输出NO,并忽略此次操作。
Input
输入一个数n表示操作的次数(n<=1*10^5) 接下来n行每行三个数x,y,p(x,y<=1*10^8,p=0 or 1)
Output
对于n行操作,分别输出n行YES或者NO
Input示例
3 1 2 1 1 3 1 2 3 0
Output示例
YES YES NO
题解:
1.一开始还以为跟这题POJ2492 A Bug's Life一样,直接种类并查集即可,结果连测试数据都过不了。后来发现:当A!=B, B!=C时,A可能等于C,也可能不等于C,而对于POJ2492,因为元素只有两种,所以A肯定等于C。自己就是受这一题的影响,一直认为A肯定等于C,思想僵化……
2.所以,同一个集合里的元素只能是相等的,即不能用种类并查集了。对此的解决策略是:为每个集合添加一个与之不相等集合的队列。
3.当规定两个集合不相等时,只需各自把对方加入到自己的“不相等”队列即可;当规定两集合相等时,即需要合并两集合,此时,就需要用到启发式合并了:把“不相等”队列小的合并到“不相等”队列大的集合上。
4.启发式合并的时间复杂度为:O(nlogn),证明:每一次把小集合合并到大集合上,则新集合的大小至少为小集合的两倍,即表明每合并一次,集合的大小可翻倍,由于只有n个元素,那么最多只能有logn次翻倍;每一次翻倍,最多只能有n个元素参与,所以时间复杂度为O(nlogn)。
5.在检验两集合是否不相等时,由于还用到了find()函数,所以总体的时间复杂度为:O(n*logn*logn)
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 2e9; 15 const LL LNF = 9e18; 16 const int MOD = 1e9+7; 17 const int MAXN = 2e5+10; 18 19 int fa[MAXN]; 20 map<int,int>M; //用于离散化 21 vector<int>s[MAXN]; //记录与这个变量不相等的变量 22 int find(int x) 23 { 24 return fa[x]==-1?x:fa[x]=find(fa[x]); 25 } 26 27 bool Union(int u, int v, int w) 28 { 29 u = find(u); 30 v = find(v); 31 32 if(u==v) //如果在同一个集合,即两变量相等,则直接判断 33 return (w==0); 34 else //不在同一个集合 35 { 36 if(s[u].size()>s[v].size()) swap(u,v); 37 bool flag = false; //判断两变量是否不相等 38 int sz = s[u].size(); 39 for(int i = 0; i<sz; i++) //用小的集合去判断 40 { 41 flag |= find(s[u][i])==v; //s[u][i]可能已经被合并到某个集合,所以要找到其当前所在的集合 42 if(flag) break; //加上这个判断,不然被卡常数 43 } 44 45 if(flag) //不过两变量不相等,则直接判断,并返回 46 return (w==1); 47 else if(w==0) //否则,如果要求两变量相等,则两者所在的集合 48 { 49 fa[u] = v; 50 sz = s[u].size(); 51 for(int i = 0; i<sz; i++) //启发式合并的关键 52 s[v].push_back(s[u][i]); 53 s[u].clear(); 54 } 55 else //如果要求两变量不相等,则各自把对方加入到自己的“不相等”队列 56 { 57 s[u].push_back(v); 58 s[v].push_back(u); 59 } 60 } 61 return true; 62 } 63 64 int main() 65 { 66 int n, m; 67 while(scanf("%d",&n)!=EOF) 68 { 69 M.clear(); 70 m = 0; 71 memset(fa,-1,sizeof(fa)); 72 for(int i = 1; i<MAXN; i++) 73 s[i].clear(); 74 for(int i = 1; i<=n; i++) 75 { 76 int u,v,w; 77 scanf("%d%d%d",&u,&v,&w); 78 if(M.find(u)==M.end()) M[u] = ++m; 79 if(M.find(v)==M.end()) M[v] = ++m; 80 81 if(Union(M[u],M[v],!w)) puts("YES"); 82 else puts("NO"); 83 } 84 } 85 }