题解:牛课 小美的朋友关系

题目

小美认为,在人际交往中,但是随着时间的流逝,朋友的关系也是会慢慢变淡的,最终朋友关系就淡忘了。
现在初始有一些朋友关系,存在一些事件会导致两个人淡忘了他们的朋友关系。小美想知道某一时刻中,某两人是否可以通过朋友介绍互相认识?
事件共有 2 种:
1. u v:代表编号 u 的人和编号 v 的人淡忘了他们的朋友关系。
2. u v:代表小美查询编号 u 的人和编号 v 的人是否能通过朋友介绍互相认识。

输入

第一行输入三个正整数 n, m, q,代表总人数,初始的朋友关系数量,发生的事件数量。
接下来 m 行,每行输入两个正整数 u, v,代表初始编号 u 的人和编号 v 的人是朋友关系。
接下来 q 行,每行输入三个正整数 op, u, v,含义如题目描述所述。

1\leq n \leq 10^9\\ 1\leq m,q\leq 10^5\\ 1\leq u, v\leq n\\ 1\leq op\leq 2
保证至少存在一次查询操作

示例

输入:

5 3 5
1 2
2 3
4 5
1 1 5
2 1 3
2 1 4
1 1 2
2 1 3

输出:

Yes
No
No

代码

import sys
from collections import defaultdict

class DisjointSet:
    def __init__(self) -> None:
        # 因为 n 可能很大,用 list 太大了
        self.p = {}

    def find(self, x):
        if x not in self.p:
            return x
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        px = self.find(x)
        py = self.find(y)
        if px != py:
            self.p[py] = px

if __name__ == '__main__':
    N, M, Q = map(int, sys.stdin.readline().strip().split())
    relats = defaultdict(set)
    for _ in range(M):
        u, v = map(int, sys.stdin.readline().strip().split())
        relats[u].add(v)
    events = []
    for _ in range(Q):
        op, u, v = map(int, sys.stdin.readline().strip().split())
        if op == 1:
            if v in relats[u]:
                relats[u].remove(v)
                events.append((op, u, v))
            elif u in relats[v]:
                relats[v].remove(u)
                events.append((op, u, v))
        else:
            events.append((op, u, v))
    ds = DisjointSet()
    # 超时的主要原因,n 太大,没必要为了空间复杂度增加时间复杂度
    # for i in range(1, N+1):
    #     for j in range(i+1, N+1):
    #         if j in relats[i]:
    #             # ds.p[i] = i
    #             # ds.p[j] = i
    #             ds.union(i, j)
    for k, v in relats.items():
        for j in v:
            ds.union(k, j)
    print_str = ''
    while(events):
        op, u, v = events.pop()
        if op == 1:
            ds.union(u, v)
        else:
            if ds.find(u) == ds.find(v):
                print_str = 'Yes\n' + print_str
            else:
                print_str = 'No\n' + print_str
    sys.stdout.write(print_str)

时间复杂度:O(max(m, n) * n)
该方法中没有使用 rank 压缩路径,使用后并查集合并的时间复杂度为 O(log^*n),则总时间复杂度变为 O(max(m, n) * log^*n)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值