并查集,离散化

人人都是好朋友

https://www.nowcoder.com/practice/431a2726d73e424896d3fd222c2c1621

思路:看到题目中提到了传递性,并且和点、边有关,首先要想到并查集。但直接用常规的连续并查集,对于1e9的点数量来说,会爆内存,因此我们需要在创建、使用并查集之前,对数据进行离散化操作

之后就是创建并查集,然后判断c为0的情况下,a和b是否已经合并过了。如果有的话,说明存在矛盾,输出"NO";否则就合并a, b,最终合并完成都没有矛盾,直接输出"YES"即可

代码:

import sys
from bisect import bisect_left

input = lambda: sys.stdin.readline().strip()

import math
inf = 10 ** 18

def I():
    return input()

def II():
    return int(input())

def MII():
    return map(int, input().split())

def GMI():
    return map(lambda x: int(x) - 1, input().split())

def LI():
    return input().split()

def LII():
    return list(map(int, input().split()))

def LFI():
    return list(map(float, input().split()))

fmax = lambda x, y: x if x > y else y
fmin = lambda x, y: x if x < y else y
isqrt = lambda x: int(math.sqrt(x))

'''

'''

# 模板来源 https://leetcode.cn/circle/discuss/mOr1u6/
class UnionFind:
    def __init__(self, n: int):
        # 一开始有 n 个集合 {0}, {1}, ..., {n-1}
        # 集合 i 的代表元是自己,大小为 1
        self._fa = list(range(n))  # 代表元
        self._size = [1] * n  # 集合大小
        self.cc = n  # 连通块个数

    # 返回 x 所在集合的代表元
    # 同时做路径压缩,也就是把 x 所在集合中的所有元素的 fa 都改成代表元
    def find(self, x: int) -> int:
        fa = self._fa
        # 如果 fa[x] == x,则表示 x 是代表元
        if fa[x] != x:
            fa[x] = self.find(fa[x])  # fa 改成代表元
        return fa[x]

    # 判断 x 和 y 是否在同一个集合
    def is_same(self, x: int, y: int) -> bool:
        # 如果 x 的代表元和 y 的代表元相同,那么 x 和 y 就在同一个集合
        # 这就是代表元的作用:用来快速判断两个元素是否在同一个集合
        return self.find(x) == self.find(y)

    # 把 from 所在集合合并到 to 所在集合中
    # 返回是否合并成功
    def merge(self, from_: int, to: int) -> bool:
        x, y = self.find(from_), self.find(to)
        if x == y:  # from 和 to 在同一个集合,不做合并
            return False
        self._fa[x] = y  # 合并集合。修改后就可以认为 from 和 to 在同一个集合了
        self._size[y] += self._size[x]  # 更新集合大小(注意集合大小保存在代表元上)
        # 无需更新 _size[x],因为我们不用 _size[x] 而是用 _size[find(x)] 获取集合大小,但 find(x) == y,我们不会再访问 _size[x]
        self.cc -= 1  # 成功合并,连通块个数减一
        return True

    # 返回 x 所在集合的大小
    def get_size(self, x: int) -> int:
        return self._size[self.find(x)]  # 集合大小保存在代表元上

def solve():
    n = II()
    edges = []
    nodes = set()
    for _ in range(n):
        a, b, c = LII()
        edges.append((a, b, c))
        nodes.add(a)
        nodes.add(b)

    nodes = sorted(nodes)
    m = len(nodes)
    uf = UnionFind(m)

    for a, b, c in edges:
        ia = bisect_left(nodes, a)
        ib = bisect_left(nodes, b)
        if c == 0 and uf.is_same(ia, ib):
            print("NO")
            return
        uf.merge(ia, ib)

    print("YES")

# t = 1
t = II()
for _ in range(t):
    solve()
#每日一题挑战#
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务