zoukankan      html  css  js  c++  java
  • POJ 2985 The kth Largest Group (树状数组学习)

    初识树状数组,确实是一种优美的数据结构,夹杂着很强的数学模型在里面。

    http://poj.org/summerschool/1_interval_tree.pdf 这里已经说明的非常清楚。

    http://dongxicheng.org/structure/binary_indexed_tree/ 这篇文章说的也是差不多的。

    重要的是去思考,为什么树形数组能够行的通,看了下面不难理解:

    C1=A1
    C2=A1+A2
    C3=A3
    C4=A1+A2+A3+A4
    C5=A5
    C6=A5+A6
    C7=A7
    C8=A1+A2+A3+A4+A5+A6+A7+A8
    …………
    C16=A1+A2+A3+A4+A5+A6+A7+A8+A9+A10+A11+A12+A13+A14+A15+A16

     

    关于这一题,是求第k大数字,树形数组的O(logn)^2算法(还可以再优化到O(logn)),可谓把它的优美程度完美体现

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    
    const int MAXN = 200010;
    // c[i]树形数组,生成c[i]的数组s[i]表示,大小为i的的集合的个数
    // f[i]节点i的父亲节点
    // a[i]以节点i为根节点的集合元素个数,初始化为1
    int c[MAXN], f[MAXN], a[MAXN];  
    int n, m;
    
    int find_set(int x)
    {
        int r = x;
        while (r != f[r])
            r = f[r];
        int p = x;
        while (p != r)
        {
            p = f[p];
            f[p] = r;
        }
        return r;
    }
    
    inline int low_bit(int x)
    {
        return x & (-x);
    }
    
    void add(int p, int d)
    {
        for (int i = p; i <= n; i += low_bit(i))
            c[i] += d;
    }
    
    int sum(int p)
    {
        int ans = 0;
        for (int i = p; i > 0; i -= low_bit(i))
            ans += c[i];
        return ans;
    }
    
    int main()
    {
        scanf("%d %d", &n, &m);
        for (int i = 1; i <= n; ++i)
            c[i] = 0, a[i] = 1, f[i] = i;
    
        add(1, n);
        int num = n;
        for (int i = 1; i <= m; ++i)
        {
            int temp;
            scanf("%d", &temp);
            if (!temp)
            {
                int x, y;
                scanf("%d %d", &x, &y);
                x = find_set(x);
                y = find_set(y);
                if (x == y)
                    continue;
                add(a[x], -1);
                add(a[y], -1);
                add(a[x] + a[y], 1);
                f[x] = y;
                a[y] += a[x];
                --num;
            }
            else
            {
                int k;
                scanf("%d", &k);
                k = num - k + 1;
                int l = 1, r = n;
                while (l <= r)
                {
                    int mid = (l + r) >> 1;
                    if (k <= sum(mid))
                        r = mid - 1;
                    else 
                        l = mid + 1;
                }
                printf("%d\n", l);
            }
        }
        return 0;
    }
    -------------------------------------------------------

    kedebug

    Department of Computer Science and Engineering,

    Shanghai Jiao Tong University

    E-mail: kedebug0@gmail.com

    GitHub: http://github.com/kedebug

    -------------------------------------------------------

  • 相关阅读:
    VINTF
    Excel 公式
    SSIS ODBC方式连接mysql数据库
    SSIS错误汇总
    linux防火墙(转)
    如何查询域名的MX、A、DNS、txt、cname记录
    IP反向解析
    Visual Studio 内存泄漏检测方法
    strcpy慎用
    main函数前后执行代码
  • 原文地址:https://www.cnblogs.com/kedebug/p/2763301.html
Copyright © 2011-2022 走看看