思维+multiset优化——cf1249E

倖福魔咒の 提交于 2019-12-02 11:26:47

正着想很难,但是反着想就容易有思路

/*
将问题转化为 挑选最多的线段,每个点的覆盖次数不超过k次
multiset里存k个右端点,表示第i层当前的最远右端点,每次来一根新线段,能填就填进并更新,不能填就更新右端点, 
线段seg 能填进当且仅当multiset的首元素<seg.s, 然后把这个首元素删除,更新为seg.t
反之找到multiset的尾元素,如果>seg.t,那么更新为seg.t 
*/
#include<bits/stdc++.h>
#include<set>
using namespace std;
#define N 200005
 
struct Seg{int l,r,id;}seg[N];
int cmp(Seg a,Seg b){return a.l<b.l;}
 
multiset<pair<int,int> >s; 
multiset<pair<int,int> >::iterator it,itt;
 
int n,k,has[N];
 
 
 
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>seg[i].l>>seg[i].r;
        seg[i].id=i;
    }
    sort(seg+1,seg+1+n,cmp);
    
    for(int i=1;i<=k;i++)s.insert(make_pair(0,0));
    
    int ans=0;
    for(int i=1;i<=n;i++){
        it=s.begin();
        pair<int,int> tmp=*it;
        if(tmp.first<seg[i].l){//能填进去 
            tmp.first=seg[i].r;
            tmp.second=seg[i].id;
            has[seg[i].id]=1;
            s.insert(tmp);
            s.erase(it);
            ans++;
        }
        else {//不能填进去 
            itt=s.end();
            itt--;
            tmp=*itt;
            if(tmp.first>seg[i].r){
                tmp.first=seg[i].r;
                has[tmp.second]=0;
                has[seg[i].id]=1;
                tmp.second=seg[i].id;
                s.insert(tmp);
                s.erase(itt);
            } 
        }
    }
    
    cout<<n-ans<<'\n'; 
    for(int i=1;i<=n;i++)
        if(!has[i])cout<<i<<" ";
}
 
/*
9 11
7 8
7 8
9 11
*/

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!