程序自动分析这道题涉及到的知识点很多 主要有三个
离散化 并查集合并 并查集查询
分析题目给出的数据范围 x最大可达1e9 但是实际上x最多只有1e5个
这样的话如果进行p[x]数组初始化将导致大量的空间浪费,因此需要将空间充分利用
从而使用离散化技术进行数据压缩 这里的离散化是不要求保序离散化的 因此使用哈希表即可
本题的核心是 如果a与b之间存在连等关系 那么使用并查集就可以把他们连成一整块
之后在单独判断不等号的部分 如果a与b不相等 但是他们的祖宗节点是一个 这样的话就证明这一串判断语句是有问题的
反之 如果ab不相等 他们也不属于同一个祖宗节点 这一串判断语句是没问题的
code
import java.util.*;
public class Main{
static HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
static int N = 200010; // n的最大值是1e5 但是每一条记录都可能会有两个数 最坏情况下两个数都不一样
// 因此离散化最差情况就是离散2e5个数 这里开得尽可能大 防止越界
static int[] p = new int[N]; // 并查集数组
static PII[] query = new PII[N]; // 这个PII数组用于存放不等关系的数字对 用于后期进行判断
static int cnt = 0; // 离散化数值 设置为全局变量 每次进行使用时都进行初始化
public static int find(int x) { // 并查集操作
if(x != p[x]) p[x] = find(p[x]);
return p[x];
}
public static int discrete(int x) { // 离散化操作
if(map.containsKey(x)) return map.get(x);
else {
map.put(x, ++cnt);
return cnt;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt(); // 轮次
while(T -- > 0) {
map.clear();
cnt = 0; // 离散化x_i的下标
int n = sc.nextInt();
for(int i = 1; i <= 2*n; ++i) { // 离散化后 数字从1开始进行计数
p[i] = i;
}
int w = 0;
for(int i = 1; i <= n; ++i) {
int a = sc.nextInt(), b = sc.nextInt(), c = sc.nextInt();
int x = discrete(a), y = discrete(b); // 将a b进行离散化
if(c == 1) // =
p[find(x)] = find(y); // 将x连接到y上
else // !=
query[w ++] = new PII(x, y); // 待查询的询问
}
boolean is_ok = true; // 是否出现问题的标记
for(int i = 0; i < w; ++i) {
if(find(query[i].a) == find(query[i].b)) {
is_ok = false;
break;
}
}
if(is_ok) System.out.println("YES");
else System.out.println("NO");
}
}
}
class PII { // 自定义数据结构存放不等关系
public int a, b;
public PII(int a, int b) { // 构造函数
this.a = a;
this.b = b;
}
}