Too Many Segments (hard version)

题目链接: Too Many Segments (hard version)

大致题意

给定两个正整数n和k, n表示有n个线段(都在OX轴上). 接下来给出n组l, r, 表示每一个线段的左右端点.

对于每一个点, 如果被线段的覆盖次数大于k, 则认为这个点是不好的, 所以我们需要删除一些线段, 使得所有的点都是好的点.

问: 最少删除多少条线段可以使得所有的点都是好的点.

解题思路

很明显, 对于每一个点, 我们都需要知道他被多少条线段所覆盖了, 而每一次给定的都是一个区间.
=> 我们需要做到快速的区间修改, 单点查询. 所以我们采用一个差分数组维护即可.

我们可以从小到大枚举每一个点, 如果当前点被覆盖的线段数目大于了k, 那么我们则需要去删除一些线段. 很容易想到, 我们应该删除能包含当前点的, 且线段要能尽可能覆盖的远的(右端点尽可能大).

这里最初我想的是二分查找, 改了半天, 发现这里其实不适用二分, 因为我们希望右端点尽可能靠右且能包含当前点的点, 无论怎么对线段进行排序, 都不能使得数组满足二分条件. 所以这里我们要采用一个大顶堆维护.

那么堆里的元素如何维护呢? 我们可以把线段按照左端点从小到大排序. 因为我们从小到大枚举每一个点, 所以当我们现在的点等于当前线段的左端点时, 表示我们当前线段可以覆盖到这个点, 则对于后续的点也是有效线段, 我们就把它入堆.

到这里思路就很清晰了, 我们从小到大枚举每一个点, 如果当前点是坏的, 则删除堆顶元素, 直至点变好为止.

AC代码

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 2E5 + 10;
int b[N]; //差分数组
void change(int l, int r, int c) { b[l] += c, b[r + 1] -= c; }
struct node {
    int first, second, id;
    bool operator< (const node& t) const {
        int l = t.first, r = t.second;
        return first < l || (first == l && second < r);
    }
};
vector<node> v; //装线段
int main()
{
    int n, k; cin >> n >> k;
    rep(i, n) {
        int l, r; scanf("%d %d", &l, &r);
        v.push_back({ l, r, i });
        change(l, r, 1);
    }
    sort(v.begin(), v.end());
    
    int sum = 0, cou = 0;
    
    priority_queue<node> q; //{ r, l, id }
    vector<int> res;
    int index = 0;
    rep(i, N - 5) {
        sum += b[i]; //计算当前点的覆盖次数
        while (index < v.size() && v[index].first == i) {
            int l = v[index].first, r = v[index].second, id = v[index].id;
            q.push({ r, l, id }); index++;
        }
        
        if (sum <= k) continue;

        while (sum > k) {
            cou++;
            auto op = q.top(); q.pop();
            int r = op.first, l = op.second;
            change(l, r, -1); 
            sum--; //本身需要树形结构维护查分数组的, 但是因为我们小到大枚举点, 其实直接把sum--是一样的;
            res.push_back(op.id);
        }
    }
    
    printf("%d\n", cou);
    for (int i = 0; i < res.size(); ++i) printf("%d%c", res[i], " \n"[i + 1 == res.size()]);
    return 0;
}

END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逍遥Fau

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值