1000C. Covered Points Count(线段覆盖问题)

You are given n

segments on a coordinate line; each endpoint of every segment has integer coordinates. Some segments can degenerate to points. Segments can intersect with each other, be nested in each other or even coincide.

Your task is the following: for every k[1..n]

, calculate the number of points with integer coordinates such that the number of segments that cover these points equals k. A segment with endpoints li and ri covers point x if and only if lixri

.

Input

The first line of the input contains one integer n

( 1n2105

) — the number of segments.

The next n

lines contain segments. The i-th line contains a pair of integers li,ri ( 0liri1018) — the endpoints of the i

-th segment.

Output

Print n

space separated integers cnt1,cnt2,,cntn, where cnti is equal to the number of points such that the number of segments that cover these points equals to i

.

Examples
Input
Copy
3
0 3
1 3
3 8
Output
Copy
6 2 1 
Input
Copy
3
1 3
2 4
5 7
Output
Copy
5 2 0 
Note

The picture describing the first example:

Points with coordinates [0,4,5,6,7,8]

are covered by one segment, points [1,2] are covered by two segments and point [3]

is covered by three segments.

The picture describing the second example:

Points [1,4,5,6,7]

are covered by one segment, points [2,3] are covered by two segments and there are no points covered by three segments.

题意:给你n条x轴上的线段,问被k条线段覆盖的点的个数,k从1到n。n<=2e5。线段坐标为long long范围

思路一:

看到这个题目的解法是建立一个数组,每读一条线段进来,就把线段上的点都加1,最后扫一遍数组计算出cnt的值,

这么做的复杂度是n*max(a[ i ]);时间很多浪费在了没有线段覆盖的地方上,所以我们想到只考虑不是0的地方,然后

新的不是0的地方与上一个不是0 的地方之间的点被线段覆盖的次数都是一样的,不是0的地方最后有n个级别,

所以复杂度是O( n )

#include<iostream>
#include<map>
using namespace std;
typedef long long LL;
const int N = 2e5+5;
map<LL,int>mp;
map<LL,int>::iterator it;
LL cnt[N];
int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		LL l,r;
		cin>>l>>r;
		mp[l]++;     //位于l处的点新加一条覆盖的线段 
		mp[r+1]--;   //位于r处的点少一条覆盖的线段
	}
	LL last=0; //当前区间的起点 
	int ans=0;
	for(it=mp.begin();it!=mp.end();it++){ //遍历每个区间 
		if(it==mp.begin()){
			last=it->first;
			ans+=it->second; //此点处线段覆盖数 
			continue;
		}
		cnt[ans]+=it->first-last;
		last=it->first;
		ans+=it->second;
	}
	for(int i=1;i<=n;i++)
	   cout<<cnt[i]<< (i==n ? "\n" : " ");
	return 0;
}

思路二:

把2n个端点排序,相同情况下起点在前,维护当前区间上一共有多少条线段(一个整型变量cnt,遇到起点+1,遇到终点-1),比较麻烦的是端点本身有多少条线段覆盖:如果遇到连续的一组重合的点,因为排序时起点在前,遍历完其中所有起点时cnt的值就是覆盖这个端点的线段数。

#include <bits/stdc++.h>
 
using namespace std;
 
#define fi first
#define se second
#define plb pair<long long, bool>
 
const int maxn = 2e5 + 5;
 
int n, cnt;
long long l, r, ans[maxn];
vector<plb> v;
 
bool cmp(const plb &p1, const plb &p2) {
	if (p1.fi == p2.fi) return (p1.se == p2.se)? false: p1.se;
	return p1.fi < p2.fi;
}
 
int main() {
	ios::sync_with_stdio(false);
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> l >> r;
		v.push_back(make_pair(l, true));
		v.push_back(make_pair(r, false));
	}
	sort(v.begin(), v.end(), cmp);
	bool ed = false;
	cnt = 1;
	for (int i = 1; i < v.size(); i++) {
		if (v[i].fi != v[i - 1].fi) {
			ans[cnt] += v[i].fi - (v[i - 1].fi) - 1;
			if (!ed) ans[cnt]++;
			else ed = false;
		}
		if (!ed && !v[i].se) {
			ans[cnt]++;
			ed = true;
		}
		cnt += v[i].se? 1: -1;
	}
	for (int i = 1; i <= n; i++) cout << ans[i] << " \n"[i == n];
	return 0;
}

猜你喜欢

转载自blog.csdn.net/islittlehappy/article/details/81041512