• ACM学习历程—HDU5700 区间交(树状数组 && 前缀和 && 排序)


    http://acm.hdu.edu.cn/showproblem.php?pid=5700

    这是这次百度之星初赛2B的第五题。省赛回来看了一下,有这样一个思路:对于所有的区间排序,按左值排序。

    然后枚举区间左值lt,计算区间右值rt最大是多少,并且满足与至少k个区间相交。关键是解决与k个区间相交这个关系。首先区间左值大于lt的是不考虑的,因为这样相交区间的左值就不是lt了。也就是考虑区间左值小于等于lt的区间中,与rt区间至少有k个相交的区间。也就是在前面的条件下,计算是否有至少k个区间右值大于等于rt

    于是,依次枚举区间,将区间右值加入树状数组。二分rt的位置,判断query(rt, n)在树状数组中的和是否大于k即可。

     

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <map>
    #include <queue>
    #include <vector>
    #include <string>
    #define LL long long
    
    using namespace std;
    
    const int maxN = 100005;
    int n, k, m;
    LL s[maxN];
    
    struct node
    {
        int lt, rt;
    
        bool operator<(node x) const
        {
            if (lt != x.lt) return  lt < x.lt;
            else return rt < x.rt;
        }
    }p[maxN];
    
    int d[maxN];
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    void add(int id,int pls)
    {
        while(id <= maxN)//id最大是maxN
        {
            d[id] += pls;
            id += lowbit(id);
        }
    }
    
    int sum(int to)
    {
        int s = 0;
        while(to > 0)
        {
            s = s + d[to];
            to -= lowbit(to);
        }
        return s;
    }
    
    int query(int from, int to)
    {
        return sum(to) - sum(from-1);
    }
    
    void input()
    {
        int t;
        s[0] = 0;
        for (int i = 1; i <= n; ++i)
        {
            scanf("%d", &t);
            s[i] = s[i-1]+t;
        }
    }
    
    int cal(int lt)
    {
        int rt = n, mid;
        while (lt+1 < rt)
        {
            mid = (lt+rt)>>1;
            if (query(mid, n) >= k) lt = mid;
            else rt = mid;
        }
        if (query(rt, n) >= k) return rt;
        else if (query(lt, n) >= k) return lt;
        else return -1;
    }
    
    void work()
    {
        for (int i = 0; i < m; ++i)
            scanf("%d%d", &p[i].lt, &p[i].rt);
        sort(p, p+m);
        memset(d, 0, sizeof(d));
        LL ans = 0;
        int to;
        for (int i = 0; i < m; ++i)
        {
            add(p[i].rt, 1);
            to = cal(p[i].lt);
            if (to != -1) ans = max(ans, s[to]-s[p[i].lt-1]);
        }
        printf("%lld
    ", ans);
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        //freopen("test.out", "w", stdout);
        while (scanf("%d%d%d", &n, &k, &m) != EOF)
        {
            input();
            work();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    java语言基础001
    Linux 使用硬盘
    Linux 系统运行命令 > 查看系统信息
    Linux rm 命令
    Linux 操作系统目录结构
    JavaScript || 事件基础
    My SQL随记 003 数据表基础操作语法
    My SQL随记 002 登陆
    My SQL随记 001 常用名词/结构化语言
    linux命令学习
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/5523629.html
Copyright © 2020-2023  润新知