CodeForces - 1000C Covered Points Count(思维+暴力)
题目链接
题目大意:
n个线段,问被这n个线段覆盖k次(k∈[1..n])的点的个数。
题目分析:想了好久啊,感觉很熟悉的题目,就是想不出做法…
把每个线段的起点终点分别存起来,起点标记为1,终点标记为-1,然后按照起点终点的位置排序。说不清,放个图吧。
比如
3
0 3
1 3
3 8
这组样例,排完序之后的顺序就是图中绿色的编号。
我们发现,1点的标记是1,二点的标记也是1,证明他们都是起点,一开始我们设一个计数变量,我们发现点被覆盖的次数就是计数变量原来的值加上当前点的标记,这就是为什么要给起点终点标记为1,-1了。然后到达一个起点或终点的时候,只需要后边的点的编号减去前边的点编号就是我们要的被覆盖的点的个数了。
但是有个地方就变得很难处理了,我们发现345这三个点重合了,按照原来的方式求的就不对了。怎么办呢。
只要把终点往后移一个就ok了。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 100;
struct node {
ll l;
int is;
bool operator <(node &a) const {
if(l != a.l) return l < a.l;
return is > a.is;
}
};
vector<node> data;
ll ans[maxn];
int main()
{
int n;
scanf("%d", &n);
ll s, e;
for(int i = 0; i < n; i++) {
scanf("%lld %lld", &s, &e);
data.push_back((node) {s, 1});
data.push_back((node) {e + 1, -1});
}
sort(data.begin(), data.end());
int len = data.size();
int cnt = 1;
for(int i = 1; i < len; i++) {
ans[cnt] += data[i].l - data[i - 1].l;
cnt += data[i].is;
}
for(int i = 1; i <= n; i++) {
printf("%lld%c", ans[i], i == n ? '\n' : ' ');
}
}