Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 50713 | Accepted: 14818 |
Description
Input
Output
Sample Input
100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5
Sample Output
3
题目要求一组数据。。。
《挑战程序设计竞赛》88页详解:对于每只动物创建3个元素i-A,i-B,i-C,并用这3 乘 N 个元素建立并查集。这个并查集维护如下信息:
1,i-x 表示i属于种类x 。
2,并查集里的每一组表示组内所有元素代表的情况都同时发生或不发生。
例如,如果i-A和i-B在同一个组里,就表示如果i属于种类A那么j一定属于种类B,如果j属于种类B那么i一定属于种类A。因此,对于每一条信息,只需要按照下面进行操作就可以了。
第一种:x和y属于同类 合并x-A和y-A,x-B和y-B,x-C和y-C。
第二种:x吃y,合并x-A和y-B,x-B和y-C,x-C和y-A。
记着和合并前需要判断是否矛盾,判断方案有二个,分别对应上面两个操作:
第一个:需要判断x-A和y-B,x-A和y-C 是否在同一组,若在同一组 则false 否则 合并。
第二个:需要判断x-A和y-A,x-A和y-C 是否在同一组(矛盾的前提为A吃A,A吃C), 若在同一组 则false 否则合并。
代码实现:
#include <cstdio> #include <cstring> #define MAX 150000+10 using namespace std; int set[MAX];//存在父节点 int ans;//记录假话数目 int n, k; void init()//初始化 { for(int i = 1; i <= n*3; i++) set[i] = i; } int find(int p) { int t; int child = p; while(p != set[p]) p = set[p]; while(child != p) { t = set[child]; set[child] = p; child = t; } return p; } void merge(int x, int y) { int fx = find(x); int fy = find(y); if(fx != fy) set[fx] = fy; } void search() { int i, j; int d, x, y; ans = 0; for(i = 0;i < k; i++) { scanf("%d%d%d", &d, &x, &y); if(x > n || y > n || x <= 0 || y <= 0)//大于n 小于0 { ans++; continue; } if(d == 1)//同一类 { if(find(x) == find(y+n) || find(x) == find(y+2*n))//属于其他两类 ans++; else//合并 { merge(x, y);//x代表种类A merge(x+n, y+n);//x+n代表种类B merge(x+2*n, y+2*n);//x+2*n代表种类C } } else { if(find(x) == find(y) || find(x) == find(y+2*n))//同一类 ans++; else { merge(x, y+n); merge(x+n, y+2*n); merge(x+2*n, y); } } } printf("%d\n", ans); } int main() { scanf("%d%d", &n, &k); init(); search(); return 0; }