codeforces 1249 D2 Too Many Segments (hard version) 贪心+树状数组

题意

给定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;
}

猜你喜欢

转载自www.cnblogs.com/xyq0220/p/11731632.html