大佬的高级IDLE
时间限制:2秒
空间限制:128M
题目描述
某厉害的大佬,自己写了个高级的IDLE。它能帮助这位大佬检测一些变量的赋值是否符合逻辑。
大佬编程时,程序中出现了一些变量(x1, x2, x3, ··· ),并且有 n 个形如 xi = xj 或 xi ≠ xj 的变量相等/不想等的约束条件。
这个IDLE能够自动判断是否可以分别给每一个变量赋予一个恰当的值,使得这 n 个条件能够同时被满足。
例如,一次编程时,约束条件为:x1 = x2, x2 = x3, x3 = x4, x1 ≠ x4。
显然这些条件无法同时被满足,因此IDLE会报错"CANNOT"。否则会提示"OK"。
现给定一些约束条件,请分别判断IDLE会提示什么。
输入描述
第1行包含1个正整数N,表示大佬的N个代码。注意这些代码之间是相互独立的。
对于每个代码,包含若干行:
第1行包含1个正整数n,表示该代码中出现的约束条件的个数。
接下来n行,每行包括3个整数 u, v, op,描述1个相等/不等的约束条件,相邻整数之间用单个空格隔开。若 op = 1 ,则该约束条件为 xu = xv ;若 op = 0 ,则该约束条件为 xu ≠ xv 。
数据范围:
1 ≤ ∑n ≤ 100000
1 ≤ u ,v ≤ 1000000000
输出描述
包括N行,代表大佬的N个代码。
第i行输出一个字符串"CANNOT"或"OK",(不包含引号,字母全大写),"CANNOT"表示给定的n个约束条件不能被同时满足,"OK"表示可以被同时满足
示例1
输入
2
2
1 2 1
1 2 0
2
1 2 1
2 1 1
输出
CANNOT
OK
说明
在第一个问题中,约束条件为:x 1 _1 1=x 2 _2 2,x 1 _1 1≠x 2 _2 2。这两个约束条件互相矛盾,因此不可被同时满足。
在第二个问题中,约束条件为:x 1 _1 1=x 2 _2 2,x 1 _1 1=x 2 _2 2。这两个约束条件是等价的,可以被同时满足。
题目分析
显然,我们要使用并查集。
对于x u _u u=x v _v v,u和v要在同一个集合中。
对于x u _u u≠x v _v v,u和v不能在同一个集合中。
因题目数据范围是1e9,故需要进行离散化。
解题思路
先处理相等的,再处理不想等的。
对于输入的u和v
- 如果x u _u u和x v _v v要相等,就把它们并入到一个集合中。
- 如果x u _u u和x v _v v要不相等,它们就不应该在同一个集合中
- 如果在,那就输出"CANNOT"并结束
- 如果所有的不想等判断完毕,都满足条件,就输出"OK"
并查集离散化
AC代码
#include <bits/stdc++.h>
using namespace std;
#define SIZE 100010
struct connect
{
int u, v, op;
} con[SIZE];
bool operator<(const connect &a, const connect &b)
{
return a.op > b.op;
} //对<的定义:操作数为1(相等)的排在前面先处理
int father[SIZE];
int getFather(int n)
{
return (n == father[n]) ? (n) : (father[n] = getFather(father[n]));
}
void Union(int u, int v) //连接两个集合
{
int fu = getFather(u);
int fv = getFather(v);
if (fu != fv)
father[fu] = fv;
}
int Rank[SIZE * 2]; //需要离散化
int main()
{
int N;
cin >> N;
while (N--) //N组测试样例
{
int n; //每组有n对
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d%d%d", &con[i].u, &con[i].v, &con[i].op);
Rank[i * 2] = con[i].u; //把l和r放入Rank中
Rank[i * 2 + 1] = con[i].v;
}
sort(Rank, Rank + n * 2); //排序
int allNum = unique(Rank, Rank + 2 * n) - Rank; //去重后,共有几种不同的元素
for (int i = 0; i < n; i++)
{
con[i].u = lower_bound(Rank, Rank + allNum, con[i].u) - Rank; //对于每一个数,离散化后对应的数
con[i].v = lower_bound(Rank, Rank + allNum, con[i].v) - Rank;
}
sort(con, con + n); //把要连接的放到前面
for (int i = 0; i < allNum; i++) //初始化father等于自己
father[i] = i;
for (int i = 0; i < n; i++)
{
int u = getFather(con[i].u);//找到father
int v = getFather(con[i].v);
if (con[i].op == 1) //如果是要合并的
Union(u, v); //就合并两个集合
else if (u == v) //不能在同一个集合中,但是却在同一个集合中
{
puts("CANNOT"); //输出CANNOT
goto loop; //结束,跳到loop处 ---->---+
}// |
}// |
puts("OK");//没有不符合条件的,输出OK |
loop:; //跳到这里 <-------<----------<-----------+
}
return 0;
}