题意

给定n个线段,线段可以相交,第\(i\)个线段覆盖的区间为\([l_i,r_i]\),问最少删除多少个线段让覆盖每个点的线段数量小于等于k。

分析

从左往右扫每个点\(x\),若覆盖点\(x\)的线段数cnt大于k,则贪心的删去覆盖点\(x\)的线段中\(r_i\)\(cnt-k\)大的线段,因为点\(x\)左边的点的被覆盖数一定已经小于等于k了,删去\(r_i\)越大的线段越优。可以用个堆来维护覆盖点\(x\)的线段,用树状数组维护覆盖每个点的线段数量。

Code

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
#define ll long long
using namespace std;
const int inf=1e9;
const int mod=1e9+7;
const int maxn=2e5+10;
int n,k;
int b[maxn];
void add(int x,int k){
	while(x<maxn) b[x]+=k,x+=x&-x; 
}
int dor(int x){
	int ret=0;
	while(x) ret+=b[x],x-=x&-x;
	return ret;
}
struct ppo{
	int l,r,i;
	bool operator <(const ppo &o) const{
		if(r==o.r&&l==o.l) return i<o.i;
		if(r==o.r) return l<o.l;
		return r<o.r;
	}
};
int ans[maxn];
struct node{
	int x,i;
};
vector<node>a[maxn];
int main(){
	ios::sync_with_stdio(false);
	//freopen("in","r",stdin);
	cin>>n>>k;
	for(int i=1,l,r;i<=n;i++){
		cin>>l>>r;
		a[l].pb(node{r,i});
		add(l,1);add(r+1,-1);
	}
	int tot=0;
	set<ppo>q;
	for(int i=1;i<maxn;i++){
		for(node x:a[i]) q.insert(ppo{i,x.x,x.i});
		int cnt=dor(i);
		while(cnt>k){
			auto it=q.end();
			--it;
			add(it->l,-1);add(it->r+1,1);
			ans[++tot]=it->i;
			q.erase(it);
			cnt--;
		}
	}
	cout<<tot<<'\n';
	for(int i=1;i<=tot;i++){
		cout<<ans[i]<<" ";
	}cout<<'\n';
	return 0;
}