• Codeforces Round #623 (Div. 2) D.Recommendations 并查集


    ABC实在是没什么好说的,但是D题真的太妙了,详细的说一下吧

    首先思路是对于a相等的分类,假设有n个,则肯定要把n-1个都增加,因为a都是相等的,所以肯定是增加t小的分类,也就是说每次都能处理一个分类,复杂度是O(n^2),这个思路很好写,优先队列随便搞一下就行了,但是题目中N = 2 * 1e5,n^2肯定是不行的,然后就是这个很巧妙的方法了,cf官方的题解我没看懂...有点尴尬,它也没给标程,但是cf的题解好像不是这个方法

    看了网上用并查集的方法,首先以t为关键字从大到小排序,然后用并查集维护当前这个应该加到哪个数字,因为是从大到小排序,所以加的数字越来越大,假设排序后是1112,首先第一次是1,不用加,把1连到2,第二次把1连到3,第三次把1连到4,然后最妙的事情就是,2这时候因为1连了2,所以这时候我们可以知道2需要连到4,因为每个数字一层一层的往上加,在合并的过程中就合并在一起了,所以保证了正确性。

    #include <cstdio>
    #include <algorithm>
    #include <map>
    using namespace std;
    const int N = 200010;
    struct news{
        int a, t;
        bool operator < (const news &o) const{
            return t > o.t;
        }
    } num[N];
    map < int, int > fa;
    
    int find(int a) {
        return (fa[a] == 0) ? a : (fa[a] = find(fa[a]));
    } 
    
    inline void merge(int a, int b) {
        int f = find(b);
        if (f != a)
            fa[a] = f;
    }
    int main() {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
            scanf("%d", &num[i].a);
        for (int i = 0; i < n; i++)
            scanf("%d", &num[i].t);
        long long ans = 0;
        sort(num, num + n);
        for (int i = 0; i < n; i++) {
            int f = find(num[i].a);
            if (f == num[i].a) {
                merge(f, f + 1);
            }
            else {
                merge(f, f + 1);
                ans = ans + 1ll * (f - num[i].a) * num[i].t;
            }
        }
        printf("%lld
    ", ans);
        return 0;
    }

    ------------恢复内容结束------------

  • 相关阅读:
    217. Contains Duplicate (leetcode)
    242. Valid Anagram(leetcode)
    JVM的逃逸分析
    有 a
    Maven 项目管理从未如此通畅
    Spring学习手札(四)谈谈Spring Bean的生命周期及作用域
    Spring学习手札(三)理解IoC 拯救不开心
    Spring学习手札(二)面向切面编程AOP
    Spring学习手札(一)
    Java提供了哪些IO方式?IO, BIO, NIO, AIO是什么?
  • 原文地址:https://www.cnblogs.com/cminus/p/12368054.html
Copyright © 2020-2023  润新知