D. The Union of k-Segments【扫描线】

D. The Union of k-Segments
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given n segments on the coordinate axis Ox and the number k. The point is satisfied if it belongs to at least k segments. Find the smallest (by the number of segments) set of segments on the coordinate axis Ox which contains all satisfied points and no others.

Input

The first line contains two integers n and k (1 ≤ k ≤ n ≤ 106) — the number of segments and the value of k.

The next n lines contain two integers li, ri ( - 109 ≤ li ≤ ri ≤ 109) each — the endpoints of the i-th segment. The segments can degenerate and intersect each other. The segments are given in arbitrary order.

Output

First line contains integer m — the smallest number of segments.

Next m lines contain two integers aj, bj (aj ≤ bj) — the ends of j-th segment in the answer. The segments should be listed in the order from left to right.

Examples
input
3 2
0 5
-3 2
3 8
output
2
0 2
3 5
input
3 2
0 5
-3 3
3 8
output
1
0 5

 

题目大意:如果一个点被至少k条线段所覆盖,那么他是满足条件的一个点,输出这些点所构成的线段集合。

用cnt记录当前点被覆盖次数,只有在扫描到题目所给线段的左端点或者右端点时会引起cnt的变化。

如果扫到左端点,意味着当前点有可能成为一段新区间的左端点,如果扫到右端点,意味着当前点可能成为一段新区间的右端点。

那么就排完序之后扫一遍。

如何排序呢?只以当前点坐标排序显然是不行的,因为会导致一些只有一个点构成的区间被忽略,还会导致一些完整区间被分成两段。

所以我们需要使得左端点优先级高于右端点,这样可以避免以上两种情况。(手动模拟一下就可以理解了)

#include<bits/stdc++.h>
using namespace std;
const int inf=2e6+10;
struct seg{
    int x;
    int d;
    seg(){}
    seg(int a,int b){
        x=a;d=b;
    }
    bool operator < (const seg & o)const {
        return x<o.x||(x==o.x&&d>o.d);
    }
}a[inf];
int n,k;
int b[inf],ans;
int main()
{
//    freopen("1.txt","r",stdin);
    scanf("%d%d",&n,&k);
    n<<=1;
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        a[i]=seg(x,i&1);
    }
    sort(a+1,a+n+1);
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(a[i].d==1){
            cnt++;
            if(cnt==k)b[++ans]=a[i].x;
        }
        else {
            if(cnt==k)b[++ans]=a[i].x;
            cnt--;
        }
    }
    printf("%d\n",ans/2);
    for(int i=1;i<ans;i+=2){
        printf("%d %d\n",b[i],b[i+1]);
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/hyghb/p/8031078.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值