其他分享
首页 > 其他分享> > NC15976 小C的周末

NC15976 小C的周末

作者:互联网

题目链接

题目

题目描述

愉快的周末到了,小C和他的N-1个朋友买了M个游戏,游戏编号从1~M。每个游戏都是多人游戏,他们打算周末一起打游戏。

小C的每个朋友都决定好了要玩哪一款游戏(会有一组人打同一款游戏),并且每人手上都有一台游戏机,这种游戏机可以通过特定的游戏机连接线连接起来。

但是,他们面临着一个问题:目前没有一个朋友的游戏机是互相连接的。所以它们必须用可用的游戏机连接线连接起来。小C决定依次使用第 i 条连接线把他的朋友 ui 和 vi 的游戏机连接起来。也就是说,假设有Q条连接线,小C只能先使用第一条,然后使用第二条,然后使用第三条。。。最后使用第Q条。

一个游戏能开始的条件是所有玩这个游戏的朋友的游戏机都被连接起来(如果不是直接连接的话,那么就必须存在一条连接它们的路径)。他们希望尽快开始比赛。

在每个游戏中,找出在添加了第几条连接线之后能开始游戏。如果在一个游戏中只有一个人玩,则输出0(因为他立马可以开始游戏)。如果不存在,则输出-1

输入描述

多组输入

第一行包含三个整数N,M,Q。

第二行给N个用空格分隔的整数,第 i 个整数代表第 i 个朋友想玩的游戏。

接下来的Q行,每行两个整数(u, v),代表电线 i 连接的两个人的电脑

1 <= N, M <= 10^5
0 <= Q <= 10^5

输出描述

对于每个游戏,输出一个整数,表示添加了第几条连接线之后能开始游戏,每行以换行符结束

示例1

输入

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

输出

3
4

说明

第一个游戏有两个人参加(1,5),在添加了第三条电线之后他们电脑互相连接

第二个游戏三个人参加(2, 3, 4),在添加第四条电线之后他们电脑互相连接

题解

知识点:并查集。

这道题用单纯的并查集维护互联关系是不够的,需要权值去表达哪些有些连了那些人。由于每个人只可能玩一个游戏,那么只要计数相等那么就说明人齐了。

所以先用 \(cnt[i]\) 记录第 \(i\) 个游戏有多少人。权值用 \(map\) 数组维护,\(map[i]\) 代表第 \(i\) 个人作为根节点时,其集合里游戏以及对应的人数。

合并时遍历被合并的权值 \(map\) 加入父集合的权值 \(map\) ,过程中用 \(ans[i]\) 记录第 \(i\) 个游戏在第几根线连接时能够开始游戏,因为要按游戏编号输出所以用游戏编号作为下标记下来。

最后按顺序输出 \(ans\) 即可。

要注意有些游戏可能只有一个人,那么在输出时先判断是不是一个人,再输出 \(0\) 即可;也有可能有些游戏没人玩,直接输出 \(-1\) 。\(ans\) 初始化为 \(-1\) 因为某些游戏可能能玩的人到最后还不够所以没更改 \(ans\) 就可以直接输出 \(-1\)。

注意是多组数据输入。

时间复杂度 \(O(q\log n + (n+m)\log m)\)

空间复杂度 \(O(n+m)\)

代码

#include <bits/stdc++.h>

using namespace std;

int fa[100007], cnt[100007], ans[100007];///fa表示连接起来的人,cnt记录每个游戏人数,ans记录答案因为最后按游戏排序
unordered_map<int, int> mp[100007];///mp[i][j] 第i个根节点的游戏种类及其对应数量

int find(int x) {
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, m, q;
    while (cin >> n >> m >> q) {
        memset(ans, -1, sizeof(ans));
        memset(cnt, 0, sizeof(cnt));
        for (int i = 1;i <= n;i++) fa[i] = i, mp[i].clear();
        for (int i = 1;i <= n;i++) {
            int tmp;
            cin >> tmp;
            cnt[tmp]++;
            mp[i][tmp] = 1;
        }
        for (int t = 1;t <= q;t++) {
            int u, v;
            cin >> u >> v;
            u = find(u);
            v = find(v);
            if (mp[u].size() > mp[v].size()) swap(u, v);
            fa[u] = v;
            for (auto [i, j] : mp[u]) {
                mp[v][i] += j;
                if (mp[v][i] == cnt[i]) ans[i] = t;
            }
        }
        for (int i = 1;i <= m;i++) {
            if (cnt[i] <= 1) cout << cnt[i] - 1 << '\n';
            else cout << ans[i] << '\n';
        }
    }
    return 0;
}

标签:cnt,游戏,int,游戏机,NC15976,周末,mp,ans
来源: https://www.cnblogs.com/BlankYang/p/16463399.html