题目

给多组线段,而每一个点的覆盖次数不超过K,每次可去除一个线段,问最少去多少线段以及线段的位置。
The only difference between easy and hard versions is constraints.

You are given nn segments on the coordinate axis OX. Segments can intersect, lie inside each other and even coincide. The ii-th segment is [li;ri] (li≤ri) and it covers all integer points j such that li≤j≤ri.

The integer point is called bad if it is covered by strictly more than kk segments.

Your task is to remove the minimum number of segments so that there are no bad points at all.

Input
The first line of the input contains two integers nn and kk (1≤k≤n≤2⋅105^{5}5) — the number of segments and the maximum number of segments by which each integer point can be covered.

The next nn lines contain segments. The ii-th line contains two integers lili and riri (1≤li≤ri≤2⋅105^{5}5) — the endpoints of the ii-th segment.

Output
In the first line print one integer mm (0≤m≤n) — the minimum number of segments you need to remove so that there are no bad points.

In the second line print mm distinct integers p1,p2,…,pm(1≤pi≤n) — indices of segments you remove in any order. If there are multiple answers, you can print any of them.

Examples
Input
7 2
11 11
9 11
7 8
8 9
7 8
9 11
7 9
Output
3
4 6 7
Input
5 1
29 30
30 30
29 29
28 30
30 30
Output
3
1 4 5
Input
6 1
2 3
3 3
2 3
2 2
2 3
2 3
Output
4
1 3 5 6
官方题解:
In this problem, we need to implement the same greedy solution as in the easy version, but faster. Firstly, let’s calculate for each point the number of segments covering it. We can do it using standard trick with prefix sums: increase cntli, decrease cntri+1 and build prefix sums on the array cnt.

Let’s maintain the set of segments that cover the current point, sorted by the right endpoint. We can do this with almost the same trick: append to the array evli the index i that says us that in the point li the i-th segment is opened. And add to the evri+1 the index −i that says us that in the point ri+1 the i-th segment is closed. Note that you need to add 11-indexed values i because +0 and −0 are the same thing actually. We can change the array cntcnt to carry the number of segments covering each point using some structure, but we don’t need to do it. Let’s maintain the variable curSub that will say us the number of segments covering the current point that was already removed. Also, let’s carry another one array sub which will say us when we need to decrease the variable curSub.

So, we calculated the array of arrays ev, the array cnt and we can solve the problem now. For the point i, let’s remove and add all segments we need, using the array evievi and add subi to curSub. Now we know that the set of segments is valid, curSub is also valid and we can fix the current point if needed. While cnti−curSub>k, let’s repeat the following sequence of operations: take the segment with the maximum right border rmaxrmax from the set, remove it, increase curSub by one and decrease subrmax+1by one.

Note that when we remove segments from the set at the beginning of the sequence of moves for the point ii, we don’t need to remove segments that we removed by fixing some previous points, and we need to pay attention to it.

Time complexity: O(nlogn).

百度翻译:

在这个问题上,我们需要实现与简单版本相同的贪婪解决方案,但速度更快。首先,让我们计算每个点覆盖它的段数我们可以使用带前缀和的标准技巧:增加cntli,减少cntri+1,并在阵列cnt上构建前缀和。
让我们保持覆盖当前点的线段集,按右端点排序我们可以使用几乎相同的技巧来实现这一点:将索引i附加到数组evli中,该索引i表示在点li中,第i段已打开再加上evri+1的指数-i,表示在ri+1点,第i段是闭合的注意,您需要添加11个索引值i,因为+0和-0实际上是相同的我们可以使用某种结构来改变阵列碳纳米管来携带覆盖每个点的段数,但我们不需要这样做。让我们维护一个变量cursub,它将告诉我们覆盖当前点的段数,这个点已经被删除了。另外,让我们携带另一个数组sub,当我们需要减少变量cursub时,它会告诉我们。
因此,我们计算了阵列的ev,阵列的cnt,我们现在可以解决这个问题对于点i,让我们使用数组eviev移除并添加我们需要的所有段,并将subi添加到curSub现在我们知道段集是有效的,curSub也是有效的,如果需要,我们可以修复当前点在重新编译时,让我们重复以下操作序列:从集合中选择最大右边界的段,删除它,将其增加一个,减少一个。
请注意,当我们在第二点的动作序列开始时从集合中移除片段时,我们不需要移除通过修复某些先前点而移除的片段,并且我们需要注意它。
时间复杂度:O(nLogn)。

思路

贪心思想,1. 以区间左端点为头,右端点由小到大排序,如果端点相同,按标号存入。
2.按排好的线段顺序,从头开始遍历每个点,判断每个点上覆盖次数,大于k时删除最长的那个区间。
3.并且真正有用的覆盖点其实就是端点(其余点都可以等价到端点上),,把每个右端点带上标号放进set(记录所有以x为左端点的线段)。

AC代码

#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
const int N=2*1e5+10;
struct node
{int id;int r;bool operator <( const node &v)const{if(r!=v.r)return r<v.r;/*右端点从小到大排序*/elsereturn id<v.id;/*下标从小到大排序*/}
};
vector<node>v[N];/*vector容器里面存放的是结构体,开了一个v[N]的数组,相当于二维数组*/
vector<int>dp;
int main()
{int n,k;scanf("%d%d",&n,&k);for(int i=1; i<=n; i++){node q;int x,y;scanf("%d%d",&x,&y);q.id=i;q.r=y;v[x].push_back(q);/*记录所有以x为左端点的线段*/}set<node>s;for(int i=1; i<N; i++){while(s.size()&&(*s.begin()).r<i)/*刚开始是不执行while循环的,若set容器中存的线段的右端点小于下一个点,那么这条边就可以删去*/s.erase(*s.begin());for(int j=0; j<v[i].size(); j++) /*遍历以顶点i为左端点的所有的线段*/s.insert(v[i][j]);/*set容器中存的是这条线段的所有信息,set容器插入元素时,会自动调整二叉树的结构,此时的‘<’的重载操作就起作用*/while(s.size()>k){dp.push_back((*s.rbegin()).id);s.erase(*s.rbegin());}}printf("%d\n",dp.size());for(int i=0; i<dp.size(); i++)printf("%d ",dp[i]);return 0;
}

Too Many Segments (hard version) CodeForces - 1249D2(贪心+容器vector+set)相关推荐

  1. Too Many Segments (easy version) CodeForces - 1249D1(贪心+差分)

    题意 给多组线段,而每一个点的覆盖次数不超过K,每次可去除一个线段,问最少去多少线段以及线段的位置. The only difference between easy and hard version ...

  2. codeforces:E2. Array and Segments (Hard version)【线段树 + 区间修改】

    分析 思路很简单 遍历每个作为最大值,然后区间不包含当前最大值的都可以减掉 easy version就可以这样暴力解决 然后求出最大差值 暴力解法 import sys input = sys.std ...

  3. 贪心 ---- Codeforces Global Round 8,B. Codeforces Subsequences[贪心,贪的乘法原理]

    题目链接 给出字符串,统计子串(子串字母可以跳跃)是codeforces的数量. 本题要求,给出子串最少数量k,构造字符串s,要求字符串s包含的字母数量最少,输出这个最少的字符串s. 题目要求是至少有 ...

  4. CodeForces - 93B(贪心+vectorpairint,double +double 的精度操作

    题目链接:http://codeforces.com/problemset/problem/93/B B. End of Exams time limit per test 1 second memo ...

  5. Codeforces 985C (贪心)

    传送门 题面: C. Liebig's Barrels time limit per test 2 seconds memory limit per test 256 megabytes input ...

  6. Skyscrapers (hard version) CodeForces - 1313C2(单调栈)

    This is a harder version of the problem. In this version n≤500000 The outskirts of the capital are b ...

  7. Skyscrapers (easy version)CodeForces - 1313C1(暴力)

    This is an easier version of the problem. In this version n≤1000 The outskirts of the capital are be ...

  8. Minimize the Permutation CodeForces - 1256(贪心)

    题意: q次询问,每次询问给你长度为n的排列,然后你每次可以选择一个位置i和i+1的数字进行交换.但是每个位置只能交换一次,问你反转若干次后,这个排列最小是多少? 题目: You are given ...

  9. Minimizing Difference CodeForces - 1244E(贪心题)

    题目 题意 官方题解: 百度翻译 思路 ac代码 题意 给出一列数,至多n个操作使其中的数+1或-1,要求得到最小的差值(最大值-最小值): You are given a sequence a1_{ ...

最新文章

  1. 谷歌旗下DeepMind开发出编程机器人,已达人类程序员平均水平!
  2. 将毫秒转换_Matlab将Unix时间戳转为可读日期
  3. 200多位专家热议“智慧城市” 建议尽快完善标准体系
  4. 华为虚拟home键关闭_苹果iPhone12或放弃静音键,学华为mate30Pro,发力虚拟按键
  5. Linux_基础指令
  6. Job_search_collection
  7. Serializable在C#中的作用及其优点
  8. mysql range用法_MySQL的常用函数
  9. 【送书】联邦学习在视觉领域的应用,揭秘2020年AAAI人工智能创新应用奖获奖案例!...
  10. wince ./configure
  11. 天龙八部服务器都需要那种系统,天龙八部排行榜系统怎么看 排行榜系统分类介绍...
  12. linux系统如何用root用户登陆,Linux用root账号创建一个新的登录账号的方法
  13. 负值之美:负margin在页面布局中的应用
  14. 深度卷积神经网络(AlexNet)
  15. android 限制后台进程,不超过4个进程 开发者选项,后台允许不超
  16. 【scratch案例教学】scratch中秋佳节 scratch创意编程 少儿编程 边玩边学 小朋友这样贺中秋
  17. windows底层编程基础
  18. vb安装过程中 ntvdm.exe[9696]中发生未处理的win32异常
  19. spi转串口 linux驱动,RT_Thread WK2124 SPI转串口芯片驱动软件包
  20. python大数据毕业设计题目100例

热门文章

  1. Android之什么场景该使用单例模式总结
  2. Android之获取屏幕和视图高和宽
  3. Android之matrix类控制图片的旋转、缩放、移动
  4. 《看聊天记录都学不会Python到游戏实战?太菜了吧》(10)无底洞的循环
  5. 《假如编程是魔法之零基础看得懂的Python入门教程 》——(五)我的魔法竟然有了一丝逻辑
  6. 计算机组成原理xchg,8088数据传送指令-计算机组成原理与汇编语言-电子发烧友网站...
  7. java 获取接口的注解_java反射注解妙用-获取所有接口说明
  8. iphone换机数据迁移_iPhone迁移数据到Android(相册与短信)
  9. 2018年最后一个月最值得关注的13个优质公号
  10. 是学习Java还是Python?一张图告诉你!