Package Delivery

本文介绍了一种算法,通过使用双指针和优先队列,针对给定区间问题,找到在保证覆盖所有元素最少次数的前提下,如何选择最小的r值和对应的区间进行操作。关键步骤包括对区间按r和l排序,利用结构体数组和标记数组进行高效操作。
摘要由CSDN通过智能技术生成

在这里插入图片描述

  • 要全部拿完,且要次数最小,那么第一次拿肯定是找r最小的,在这个最小的r处第一次拿
  • 此时可能有很多区间覆盖了这个r,为了让拿的次数最小,要让下一次拿的时间尽可能晚,因此在这些覆盖了r的区间里选择r最小的k个区间
  • 用一个结构体数组a记录l和r和编号,再用一个完全相同的结构体数组b复制一份,a数组按照r从小到大排序,b数组按照l从小到大排序;del数组,以编号为下标,记录该区间是否已经被删除
  • 双指针,遍历a数组,如果当前这个已经被删除,则continue;i指针为a数组的指针,j指针为b数组的指针;i每次前进一个,将b数组中当前的r覆盖到的区间(记录r和编号)全部放入优先队列中(覆盖的判断方式:l小于等于r即可);然后删除小于等于k个
  • 每一次当前没有被删除的区间中r最小的,将这个最小的r作为标准,然后将所有还未被放入过优先队列的l比当前r小的全都放入优先队列,然后删掉最多k个,同时标记它们已经被删除
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#define endl '\n'
#define _(a) cout << #a << ": " << (a) << "    "
using namespace std;
const int N = 1e5 + 10;
typedef pair<int, int> PII;

int n, k;
struct node {
    int l, r, id;
}a[N], b[N];
struct cmp {
    bool operator() (const PII &x, const PII &y) {
        return x.first > y.first;
    }
};
bool del[N];

bool cmpr(node a, node b) {
    return a.r < b.r;
}
bool cmpl(node a, node b) {
    return a.l < b.l;
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int _; cin >> _;
    while (_ -- ) {
        cin >> n >> k;
        int ans = 0;
        for (int i = 1; i <= n; ++ i) {
            cin >> a[i].l >> a[i].r;
            a[i].id = i;
            b[i] = a[i];
            del[i] = false;
        }
        sort(a + 1, a + n + 1, cmpr);
        sort(b + 1, b + n + 1, cmpl);
        priority_queue<PII, vector<PII>, cmp> pq;
        int j = 1;
        for (int i = 1; i <= n; ++ i) {
            if (del[a[i].id]) continue;
            while (j <= n && b[j].l <= a[i].r) {
                pq.push({b[j].r, b[j].id});
                j ++ ;
            }
            ans ++ ;
            for (int t = 1; t <= k; ++ t) {
                if (pq.empty()) break;
                PII now = pq.top(); pq.pop();
                del[now.second] = true;
            }
        }
        cout << ans << endl;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值