题目链接
https://codeforces.com/contest/1249/problem/D2
题目大意
给你 N 条线段,每条线段覆盖的点为 [Li , Ri] ,如果某个点被超过 k 条线段覆盖,那么这个点为坏点,
问最少可以去掉哪些线段可以使得没有坏点
解题思路
线段树 + multiset
挺水的一题。
很显然在满足 L <= 当前坏点位置时 ,删除 R 最大的线段是最优的
对于每个线段它覆盖的点为 [Li , Ri] , 那么就用线段树对应维护这个区间内的所有点
在所有线段都操作完毕后再将坏点取出,以及对线段排序
然后遍历所有坏点 , 将左端点 L 小于当前坏点的线段存入 multiset ,存完后再删除其中 R 最大的几项即可
AC_Coder
#include<bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define int long long
#define ll long long
#define il inline
#define fi first
#define se second
#define pb push_back
using namespace std;
struct Tree
{
ll l,r,sum,lazy,maxn,minn;
} tree[1000000];
il void push_up(ll rt)
{
tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
tree[rt].maxn=max(tree[rt<<1].maxn,tree[rt<<1|1].maxn);
tree[rt].minn=min(tree[rt<<1].minn,tree[rt<<1|1].minn);
}
il void push_down(ll rt , ll length)
{
if(tree[rt].lazy)
{
tree[rt<<1].lazy+=tree[rt].lazy;
tree[rt<<1|1].lazy+=tree[rt].lazy;
tree[rt<<1].sum+=(length-(length>>1))*tree[rt].lazy;
tree[rt<<1|1].sum+=(length>>1)*tree[rt].lazy;
tree[rt<<1].minn+=tree[rt].lazy;
tree[rt<<1|1].minn+=tree[rt].lazy;
tree[rt<<1].maxn+=tree[rt].lazy;
tree[rt<<1|1].maxn+=tree[rt].lazy;
tree[rt].lazy=0;
}
}
il void build(ll l , ll r , ll rt , ll *aa)
{
tree[rt].lazy=0;
tree[rt].l=l;
tree[rt].r=r;
if(l==r)
{
tree[rt].sum=aa[l];
tree[rt].minn=tree[rt].sum;
tree[rt].maxn=tree[rt].sum;
return;
}
ll mid=(l+r)>>1;
build(l,mid,rt<<1,aa);
build(mid+1,r,rt<<1|1,aa);
push_up(rt);
}
il void update_range(ll L , ll R , ll key , ll rt)
{
if(tree[rt].r<L||tree[rt].l>R)return;
if(L<=tree[rt].l&&R>=tree[rt].r)
{
tree[rt].sum+=(tree[rt].r-tree[rt].l+1)*key;
tree[rt].minn+=key;
tree[rt].maxn+=key;
tree[rt].lazy+=key;
return;
}
push_down(rt,tree[rt].r-tree[rt].l+1);
ll mid=(tree[rt].r+tree[rt].l)>>1;
if(L<=mid)update_range(L,R,key,rt << 1);
if(R>mid)update_range(L,R,key,rt << 1 | 1);
push_up(rt);
}
il ll query_range(ll L, ll R, ll rt)
{
if(L<=tree[rt].l&&R>=tree[rt].r)
{
return tree[rt].sum;
}
push_down(rt,tree[rt].r-tree[rt].l+1);
ll mid=(tree[rt].r+tree[rt].l)>>1;
ll ans=0;
if(L<=mid)ans+=query_range(L,R,rt << 1);
if(R>mid)ans+=query_range(L,R,rt << 1 | 1);
return ans;
}
const int N = 2e5 + 10;
struct node
{
int l , r , id;
bool operator < (node const & a) const
{
if(l == a.l) return r < a.r;
return l < a.l;
}
} x[N];
int n , k , a[N] , b[N] , cnt;
multiset<pair<int , int>>s;
vector<int>ans;
signed main()
{
cin >> n >> k;
build(1 , N - 10 , 1 , a);
rep(i , 1 , n)
{
cin >> x[i].l >> x[i].r;
update_range(x[i].l , x[i].r , 1 , 1);
x[i].id = i;
}
rep(i , 1 , N - 10)
if(query_range(i , i , 1) >= k)
b[++ cnt] = i;
sort(x + 1 , x + 1 + n);
int now = 1;
rep(i , 1 , cnt)
{
while(x[now].l <= b[i] && now <= n) s.insert(make_pair(-x[now].r , x[now].id)) , now ++ ;
int tot = query_range(b[i] , b[i] , 1) - k;
while(tot > 0)
{
auto it = *s.begin();
update_range(b[i] , -it.fi , -1 , 1);
s.erase(it);
tot -- ;
ans.pb(it.se);
}
}
cout << ans.size() << "\n";
for(auto i : ans) cout << i << " ";
cout << '\n';
return 0;
}