Too Many Segments (hard version) CodeForces - 1249D2(树状数组+set)

The only difference between easy and hard versions is constraints.

You are given n segments on the coordinate axis OX. Segments can intersect, lie inside each other and even coincide. The i-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 k 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 n and k (1≤k≤n≤2⋅105) — the number of segments and the maximum number of segments by which each integer point can be covered.

The next n lines contain segments. The i-th line contains two integers li and ri (1≤li≤ri≤2⋅105) — the endpoints of the i-th segment.

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

In the second line print m 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
思路:数据量这么大,就不能像简单版本那样暴力了。
排序方式其实不唯一,不必拘泥于某一种排序。我的排序方式按照右端点由大到小排序。和第一题思路一样,对于某一个坏点,我们肯定希望的是删除覆盖它并且右端点最靠右的点。还是一样遍历所有的点,树状数组求出覆盖在这个点上线段数。我们首先将集合中右端点小于当前值的线段去除,这些线段对后面的点不会再有影响了,然后再加入以当前点为左端点的线段。如果树状数组求得当前值大于k的话,不断在集合中删除线段,因为集合中的线段按照右端点由大到小排序,所以我们直接删除顶部的就可以了,直到不大于k。一直这样操作直到最后。复杂度为O(nlogn)。
(ps:突然发现不用树状数组也可以,因为加入以当前点为左端点的线段之后,如果集合的大小大于k了,就代表有大于k条线段覆盖在当前点上了。。这样耗时可能少一点点)
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=2e5+100;
struct node{
	int x,y,id;
	node(){}
	node(int a,int b,int c)
	{
		x=a,y=b,id=c;
	}
	bool operator<(const node &a)const{
		if(y==a.y&&x==a.x)return id<a.id;
		if(y!=a.y) return y>a.y;
		else return x<a.x;
	}
};
int c[maxx];
vector<node> v[maxx]; 
int n,k;

inline int lowbit(int x){return x&-x;}
inline void update(int x,int v)
{
	while(x<maxx)
	{
		c[x]+=v;
		x+=lowbit(x);
	}
}
inline int query(int x)
{
	int ans=0;
	while(x)
	{
		ans+=c[x];
		x-=lowbit(x);
	}
	return ans;
}
int main()
{
	memset(c,0,sizeof(c));
	scanf("%d%d",&n,&k);
	int x,y,sx=maxx,sy=0;
	set<node> s;
	vector<int> ans;ans.clear();
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&x,&y);
		update(x,1);
		update(y+1,-1);
		sx=min(sx,x);
		sy=max(sy,y);
		v[x].push_back(node(x,y,i));
	}
	int num,j=0;
	for(int i=sx;i<=sy;i++)
	{
		while(s.size()&&(*s.rbegin()).y<i) s.erase(*s.rbegin());
		num=query(i);
		for(int j=0;j<v[i].size();j++) s.insert(v[i][j]);
		while(num>k)
		{
			update((*s.begin()).x,-1);
			update((*s.begin()).y+1,1);
			num--;
			ans.push_back((*s.begin()).id);
			s.erase(*s.begin());
		}
	}
	cout<<ans.size()<<endl;
	sort(ans.begin(),ans.end());
	for(int i=0;i<ans.size();i++) cout<<ans[i]<<" ";
	cout<<endl;
	return 0;
}

很好的一道题目!!
努力加油a啊,(o)/~

发布了596 篇原创文章 · 获赞 47 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/starlet_kiss/article/details/105124557
今日推荐