cf Educational Codeforces Round 46 C. Covered Points Count

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tengfei461807914/article/details/82010755

原题:
C. Covered Points Count
time limit per test3 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
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 li≤x≤ri.
Input
The first line of the input contains one integer n (1≤n≤2⋅10^5) — the number of segments.

The next
n lines contain segments. The i-th line contains a pair of integers li,ri (0≤li≤ri≤10^18) — 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
3
0 3
1 3
3 8
output
6 2 1

input
3
1 3
2 4
5 7
output
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个线段,线段的范围从0到10^18,问你这n个线段覆盖当中,坐标点被覆盖了i条线段的点各是多少。

代码:

#include <bits/stdc++.h>

using namespace std;


typedef long long ll;
const int maxn=200005;
struct node
{
    ll a;
    int b;
};

int cmp(const node &n1,const node &n2)
{
    if(n1.a!=n2.a)
        return n1.a<n2.a;
    return n1.b>n2.b;
}

node no[maxn*2];
ll mark[maxn];
int n;
int main()
{

    ios::sync_with_stdio(false);
    while(cin>>n)
    {
        int ind=0;
        ll l,r;
        memset(mark,0,sizeof(mark));
        for(int i=1;i<=n;i++)
        {
            cin>>l>>r;
            r++;
            no[++ind]=node{l,1};
            no[++ind]=node{r,-1};
        }
        sort(no+1,no+1+ind,cmp);
        ll ans=0,cnt=1;

        for(int i=2;i<=ind;i++)
        {
            mark[cnt]+=no[i].a-no[i-1].a;
            cnt+=no[i].b;
        }
        for(int i=1;i<=n;i++)
        {
            if(i!=n)
                cout<<mark[i]<<" ";
            else
                cout<<mark[i]<<endl;
        }

    }


    return 0;
}

思路:

这题看起来很像裸的线段树哈,但是线段的范围相当夸张,到了10^18,需要离散化。而且,在线段插入的过程当中是需要计算整个区间当中的坐标点被覆盖了多少次,为了降低复杂度,得使用延迟标记,等等~~ 很明显,这题不能这么搞,呵呵。

如果这题不能对线段的范围进行操作,那么就一定是对给定的这几个点进行操作,在纸上画一画可以发现,把所有线段的端点在一维数轴上标出,相邻的两个端点之间是有关系的。

也就是如果当前的端点是起点,下一个端点也是起点,那就说明下一个点一定是比当前端点多覆盖了一条线段,如下图第一个箭头。
这里写图片描述

同理,遇到一个端点是起点,那么一定是比当前点减少了一条线段的覆盖。

这样,从第一个端点开始,每次判断端点类型,决定端点被覆盖数即可,最后端点之间的距离也就是一个完整线段覆盖的所有坐标点,相邻端点相减即可。

此外,有一个问题,如图,如果坐标点有重合怎么办? 可以将重合的端点再次标记,不过太麻烦,题解当中有一个很巧妙的办法,就是将右端点拉长一个单位,不过这样会把不同覆盖点的数量有所增加,此时,将计算点数目的 [ a i , a i + 1 ] 区间改成计算 [ a i , a i + 1 ) 的左闭右开区间,就把延长后的多余点减掉了,好牛X的想法呀!

猜你喜欢

转载自blog.csdn.net/tengfei461807914/article/details/82010755