Skip to content

ABC329F Colored Ball

原题链接:F - Colored Ball

Tag:启发式合并

题目描述

给定 \(N\) 个盒子,每个盒子里面有一个颜色为 \(C_i\) 的小球。 有 \(Q\) 次操作,每次操作将第 \(a_i\) 个盒子中的球都放到第 \(b_i\) 个盒子里面, 你需要在每次操作后输出当前操作结束后第 \(b_i\) 个盒子里面有多少个不同颜色的小球。

如果盒子为空,输出 \(0\) 即可。

数据说明:

  • \(1 \leq N, Q \leq 200000\)
  • \(1 \leq C_i \leq N\)
  • \(1 \leq a, b \leq N\)
  • \(a \neq b\)

分析

按照题目来说很好想到用 \(\text{set}\) 来维护集合。

由于需要合并集合,可以想到启发式合并, 每次合并两个集合的时候我们遍历小的集合, 把其中所有的元素都插入到较大的集合当中。 因为题目要我们输出的是 \(b_i\) 集合的球种类, 我们固定把小的合并到大的中, 可以通过 \(\text{swap}\) 来解决固定是合并到 \(b_i\) 这个问题。 这个 \(\text{STL}\)\(\text{swap}\)\(O(1)\) 的。

上述做法中操作的次数为 \(O(nlogn)\), 单次 \(\text{set}\) 的插入复杂度为 \(O(logn)\), 因此上述做法的综复杂度为 \(O(nlog^2{n})\)

代码实现

void NeverSayNever() {
    int n,q; cin >> n >> q;
    vector<set<int>> vec(n);
    for(auto &x : vec){
        int tmp; cin >> tmp;
        x.insert(tmp);
    }
    while(q--){
        int a,b; cin >> a >> b;
        a--,b--;
        if(vec[a].size() < vec[b].size()){
            for(auto &x : vec[a]){
                vec[b].insert(x);
            }
            vec[a].clear();
        }else{
            for(auto &x : vec[b]){
                vec[a].insert(x);
            }
            vec[b].clear();
            swap(vec[a],vec[b]);
        }
        cout << vec[b].size() << endl;
    }
}

日志

本页面创建于 2024/09/13 10:41