标签:Many int 题解 Segments 端点 ans include segment 线段
CF1249D2 Too Many Segments (hard version)
思路
区间覆盖问题,又是求最小的删除个数,可以想到是贪心。
我们按顺序考虑,假设当前点 $1 \cdots i-1$ 都已经合法,目前要处理不合法的 $i$。
那么在当前所有覆盖着点 $i$ 的线段中,自然要不断选择右端点最大的线段进行删除,直到点 $i$ 合法。
正确性也不难证明:前 $i-1$ 个点已经合法,不用考虑,选择右端点最大的线段对于其它决策具有决策包容性。
那么我们只需要先将所有线段按左端点排序,在遍历到点 $i$ 的时候将可以覆盖点 $i$ 的线段放入大根堆中。
其中大根堆以右端点大为优先级更高,然后当点 $i$ 不合法时,不断取出堆顶,删除该线段。如此往复知道遍历结束即可。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 #include <vector> 6 #include <utility> 7 using namespace std; 8 const int maxn = 200005; 9 int sum[maxn],n,k; 10 struct segment { 11 int l,r,id; 12 segment() { 13 l = r = id = 0; 14 } 15 segment(int l,int r):l(l),r(r){} 16 bool operator < (const segment& p)const { 17 return r < p.r; 18 } 19 }a[maxn]; 20 bool cmp(segment x,segment y) { 21 return (x.l ^ y.l) ? x.l < y.l : x.r < y.r; 22 } 23 priority_queue<segment> q; 24 vector<int> ans; 25 int main() { 26 scanf("%d%d",&n,&k); 27 for(int i = 1;i <= n;++ i)scanf("%d%d",&a[i].l,&a[i].r),a[i].id = i,++ sum[a[i].l],-- sum[a[i].r + 1]; 28 sort(a + 1 , a + 1 + n , cmp); 29 int j = 1; 30 int cnt = 0; 31 for(int i = a[1].l;i <= a[n].r;++ i) { 32 for(;j <= n&&a[j].l <= i;++ j)q.push(a[j]); 33 sum[i] += sum[i - 1]; 34 while(sum[i] > k) { 35 segment w = q.top(); 36 q.pop(); 37 -- sum[i]; 38 ++ sum[w.r + 1]; 39 ans.push_back(w.id); 40 } 41 } 42 printf("%d\n",ans.size()); 43 sort(ans.begin() , ans.end()); 44 for(int i = 0;i < ans.size();++ i)printf("%d ",ans[i]); 45 return 0; 46 }QAQ
标签:Many,int,题解,Segments,端点,ans,include,segment,线段
来源: https://www.cnblogs.com/663B/p/15787682.html
本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。