https://codeforces.com/blog/entry/70779
分析:想到在要删去一条线段时贪心的选取右坐标最长的那一个肯定正确。
就可以利用排序,即set的自动排序再重定义运算符来处理(按左坐标的顺序插入,按右坐标大小排序),用size()表示覆盖的边数,坐标从左到右一个个该删删该增增,维护一遍。
一个技巧:vector<Node> segs[maxn] 的Node 是右坐标 和 线段的序号,而用数组下标用左坐标来表示,就能够实现上述的坐标上扫一遍的处理。
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5+10; struct Node{ int r; int idx; }; bool operator < (Node a,Node b){ if(a.r != b.r) return a.r<b.r; return a.idx<b.idx; } vector<Node> segs[maxn]; set<int> ans; int n,k,x,y; int main(){ ios::sync_with_stdio(false); cin.tie(0); cin>>n>>k; for(int i=0; i<n; i++){ cin>>x>>y; Node temp; temp.r = y; temp.idx = i; segs[x].push_back(temp); } set<Node> s; for(int i=0; i<maxn; i++){ while(s.size() && (*s.begin()).r<i ){ s.erase(s.begin()); } for(Node it: segs[i]){ s.insert(it); } while(s.size() > k){ ans.insert( (*s.rbegin()).idx ); s.erase( *(s.rbegin()) ); } } cout<<ans.size()<<endl; for(int it : ans){ cout<<it+1<<" "; } cout<<endl; } //c.begin() 返回一个迭代器,它指向容器c的第一个元素 // c.end() 返回一个迭代器,它指向容器c的最后一个元素的下一个位置 // c.rbegin() 返回一个逆序迭代器,它指向容器c的最后一个元素 // c.rend() 返回一个逆序迭代器,它指向容器c的第一个元素前面的位置