线段覆盖

【题目描述】

在一个数轴上有n(n <= 1000000)条线段,每条线段的两端可用整数坐标表示,坐标范围为[0,1018],每条线段都有一个价值Ci(0 <= C<= 109),请从n条线段中选出若干条线段,使得这些线段两两不覆盖(端点可以重合)且线段价值之和最大。

【输入描述】

第一行输入一个整数n,表示有多少条线段;

接下来n行,每行输入三个整数Ai、Bi、Ci,分别代表第i条线段的左端点、右端点(左端点 < 右端点)和价值。

【输出描述】

输出一个数,表示能够获得的最大价值。

【样例输入】

3

1 2 1

2 3 2

1 3 4

【样例输出】

4

源代码:

#include<cstdio>
#include<algorithm>
using namespace std;
struct Node
{
    unsigned long long L,R,S;
}i[1000001];
unsigned long long f[1000001]={0}; //注意数据范围。
int n;
bool Rule(Node t1,Node t2)
{
    return t1.R<t2.R;
}
int Find(int t) //二分法。
{
    int Left=0,Right=t-1,Mid=0;
    while (Left<=Right)
    {
        Mid=(Left+Right)>>1;
        if (i[Mid].R>i[t].L)
          Right=Mid-1;
        else
          Left=Mid+1;
    }
    if (i[Right].R<=i[t].L)
      return Right;
    else
      return Left; //无合法情况时,Right会一直下降,直至为-1。
}
int main() //普通的线段覆盖DP加了个二分查找。
{
    scanf("%d",&n);
    for (int a=1;a<=n;a++)
      scanf("%lld%lld%lld",&i[a].L,&i[a].R,&i[a].S);
    sort(i+1,i+n+1,Rule);
    for (int a=1;a<=n;a++) //前多少条线段。
      f[a]=max(f[a-1],f[Find(a)]+i[a].S);
    printf("%lld",f[n]);
    return 0;
}
posted @ 2016-10-05 21:34  前前前世。  阅读(343)  评论(0编辑  收藏  举报