题意:给出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;
}