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
原文地址:https://www.cnblogs.com/andyqsmart/p/5523629.html