D2. Too Many Segments(线段树)

题意:给出n个线段,要求同一个点不能有超过k条线段覆盖。求最少要删多少条线段。

思路:要求最少删除多少线段,只要尽量多的线段重叠就好了,所以可以对区间进行先按右端点从小到大, 若右相等则按左从小到大这样排序。然后依次插入这些区间, 若一个区间满足这个区间内的点的最大被覆盖次数还不足 k, 那么就将这个区间覆盖下去, 否则加上这条边的话,就会产生坏点,这条边同时也是产生坏点的最长的边,所以这个区间就将被删去, 加入答案. 这个过程需要区间加和查询区间最大值, 用线段树.

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5 + 10;
int n, k, tree[N << 2], lz[N << 2];
vector<int> ans;
struct node {
    int id, l, r;
    bool operator <(const node &a)const {
        if(r == a.r)
            return l < a.l;
        return r < a.r;
    }
} no[N];
void down(int rt, int ln, int rn) {
    if(lz[rt]) {
        lz[rt << 1] += lz[rt];
        lz[rt << 1 | 1] += lz[rt];
        tree[rt << 1] += lz[rt];
        tree[rt << 1 | 1] += lz[rt];
        lz[rt] = 0;
    }
}
void ins(int L, int R, int l, int r, int rt) {
    if(L <= l && r <= R) {
        tree[rt]++;
        lz[rt]++;
        return;
    }
    int m = l + r >> 1;
    down(rt, m - l + 1, r - m);
    if(m >= L)
        ins(L, R, l, m, rt << 1);
    if(m < R)
        ins(L, R, m + 1, r, rt << 1 | 1);
    tree[rt] = max(tree[rt << 1 | 1], tree[rt << 1]);
}
int ask(int L, int R, int l, int r, int rt) {
    if(L <= l && r <= R)
        return tree[rt];
    int m = l + r >> 1;
    down(rt, m - l + 1, r - m);
    int ans = 0;
    if(m >= L)
        ans = max(ans, ask(L, R, l, m, rt << 1));
    if(m < R)
        ans = max(ans, ask(L, R, m + 1, r, rt << 1 | 1));
    tree[rt] = max(tree[rt << 1 | 1], tree[rt << 1]);
    return ans;
}
int main() {
    ios::sync_with_stdio(0);
    cin >> n >> k;
    for(int i = 1; i <= n; i++) {
        cin >> no[i].l >> no[i].r;
        no[i].id = i;
    }
    sort(no + 1, no + n + 1);
    for(int i = 1; i <= n; i++) {
        if(ask(no[i].l, no[i].r, 1, N, 1) < k)
            ins(no[i].l, no[i].r, 1, N, 1);
        else
            ans.push_back(no[i].id);
    }
    cout << ans.size() << endl;
    for(auto s : ans)
        cout << s << " ";
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值