codeforces 612D The Union of k-Segments (sorting)

好久没写过博客了。。。 这学期开始要好好分配时间了,在一个时间点中不要将精力太过于分散了,这样感觉最后什么都学不到,什么都学不好。。
这学期好好训练!
链接:http://codeforces.com/contest/612/problem/D
题意:
给定n条线段,给出一个k,定义一个点符合条件的是被至少k条线段覆盖到,要求找出一个最小的线段集合,这个集合能够包含所有满足那个条件的点。
(这里要注意这个线段集合中的线段不需要是之前的线段了,只要由一开始给的n条线段的端点集中的元素构成的就可以了。)
思路:
这类型的题目,马上想到之前类似的题目,利用在线段的两端分别做不同的标志位,比如在左端点标记为 +1 ,右端点标记为-1,不是端点的都为0,那么可以从左边加到右边。(这是个经典方法,在一些贪心判断中很常用),从这个类似的角度去思考。
解题方法:
但是这个又有一点点的不一样,这是要求出包含所有满足点的最小线段集,会发现这个线段集中的线段端点肯定都在之前线段端点集中。那么也可以按照之前的方法进行标记,但是这时候只需要将排序将每个端点加起来,加到一个端点的时候,有两种有用的情况
1) 之前是k-1 ,加完变成 k ,那么这个点就是最小线段集中的一个左端点。
2) 之前是k,加完变成了k-1,那么这个点肯定是一个右端点。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define M 10000009
int n,k;
typedef struct
{
    int num;
    int typ;
}Node;
Node node[M];
bool cmp(Node a,Node b)
{
    if(a.num != b.num) return a.num < b.num;
    return a.typ > b.typ;
}
vector< pair<int,int> > ans;
int main()
{
    scanf("%d %d",&n,&k);
    int tot = 0;
    for(int i = 0;i < n;i++)
    {
        scanf("%d",&node[tot].num);
        node[tot++].typ = 1;
        scanf("%d",&node[tot].num);
        node[tot++].typ = -1;
    }
    sort(node,node+tot,cmp); //sort 将左边的点排在前面, 如果一个点既是线段的左端点,又是另一个的右端点,将左端点的放在前面
    int cnt = 0;
    int op;
    for(int i = 0;i < tot;i++)
    {
        if(cnt == k-1 && node[i].typ == 1) op = node[i].num; 
        if(cnt == k && node[i].typ == -1)
        {
            ans.push_back(make_pair(op,node[i].num));
        }
        cnt += node[i].typ;
    }
    printf("%d\n",ans.size());
    int ss = ans.size();
    for(int i = 0;i < ss;i++)
    {
        printf("%d %d\n",ans[i].first,ans[i].second);
    }
    return 0;
}

你可能感兴趣的:(codeforces)