Covered Points Count
题目描述
You are given n n 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 ] k \in [1..n] k∈[1..n] , calculate the number of points with integer coordinates such that the number of segments that cover these points equals k k k . A segment with endpoints l i l_i li and r i r_i ri covers point x x x if and only if l i ≤ x ≤ r i l_i \le x \le r_i li≤x≤ri .
输入格式
The first line of the input contains one integer n n n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 1 \le n \le 2 \cdot 10^5 1≤n≤2⋅105 ) — the number of segments.
The next n n n lines contain segments. The i i i -th line contains a pair of integers l i , r i l_i, r_i li,ri ( 0 ≤ l i ≤ r i ≤ 1 0 18 0 \le l_i \le r_i \le 10^{18} 0≤li≤ri≤1018 ) — the endpoints of the i i i -th segment.
输出格式
Print n n n space separated integers c n t 1 , c n t 2 , … , c n t n cnt_1, cnt_2, \dots, cnt_n cnt1,cnt2,…,cntn , where c n t i cnt_i cnti is equal to the number of points such that the number of segments that cover these points equals to i i i .
题面翻译
题目大意:
给你n个区间,求被这些区间覆盖层数为 k ( k < = n ) k(k<=n) k(k<=n)的点的个数
输入格式:
第一行一个整数, n n n, n < = 2 ∗ 1 0 5 n<=2*10^5 n<=2∗105
以下 n n n行,每行有两个整数,即这个区间的左右端点 l , r ( 0 < = l < = r < = 1 0 18 ) l,r(0<=l<=r<=10^{18}) l,r(0<=l<=r<=1018)
输出格式:
n n n个整数,即每个被覆盖层数对应的点的个数
样例 #1
样例输入 #1
3
0 3
1 3
3 8
样例输出 #1
6 2 1
样例 #2
样例输入 #2
3
1 3
2 4
5 7
样例输出 #2
5 2 0
提示
The picture describing the first example:
Points with coordinates [ 0 , 4 , 5 , 6 , 7 , 8 ] [0, 4, 5, 6, 7, 8] [0,4,5,6,7,8] are covered by one segment, points [ 1 , 2 ] [1, 2] [1,2] are covered by two segments and point [ 3 ] [3] [3] is covered by three segments.
The picture describing the second example:
Points [ 1 , 4 , 5 , 6 , 7 ] [1, 4, 5, 6, 7] [1,4,5,6,7] are covered by one segment, points [ 2 , 3 ] [2, 3] [2,3] are covered by two segments and there are no points covered by three segments.
思路
看到这个题第一时间想到用前缀和扫一遍,但看一眼数据范围可以发现
l
0
<
=
l
<
=
r
<
=
1
0
18
l0<=l<=r<=10^{18}
l0<=l<=r<=1018很明显会爆,再看一眼会发现
n
<
=
2
∗
1
0
5
n<=2*10^5
n<=2∗105可以将所有区间的左右端点存起来再排序,之后扫一遍就可以了
那么我们就用一个
n
o
w
now
now 记录当前段被覆盖了几次,然后枚举排序后前缀和改变的节点,把每次改变之前的一段中的节点数加入覆盖数为
n
o
w
now
now 的答案,最后修改
n
o
w
now
now 的值即可。还要注意一点:每一个线段的左端点和右端点的节点类型是不一样的,遇到左端点要
n
o
w
+
+
now++
now++,右端点则要
n
o
w
−
−
now--
now−−。
代码
/*************************************************
Note:CF1000C
*************************************************/
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <stdio.h>
#include <iostream>
#include <vector>
#include <iomanip>
#include <string.h>
#include <algorithm>
#include <cmath>
#include <cstring>
#define ll long long
#define ull unsigned long long
using namespace std;
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
inline int read()
{
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
int n;
ll ans[N];
struct node
{
ll p;
int k;
};
bool cmp(node x, node y)
{
return x.p == y.p ? x.k < y.k : x.p < y.p;
}
vector<node> q;
int main()
{
ll l, r;
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> l >> r;
q.push_back((node){l, 1});
q.push_back((node){r + 1, -1});
}
sort(q.begin(), q.end(), cmp);
ll last = 0, now = 0;
for (int i = 0; i < q.size(); i++)
{
ll nex = q[i].p;
ans[now] += q[i].p - last;
now += q[i].k, last = nex;
}
for (int i = 1; i <= n; i++)
cout << ans[i] << " ";
}