题目描述
Description
数轴上有n条线段,线段的两端都是整数坐标,坐标范围在0~1000000,每条线段有一个价值,请从n条线段中挑出若干条线段,使得这些线段两两不覆盖(端点可以重合)且线段价值之和最大。
输入描述
Input Description
第一行一个整数n,表示有多少条线段。
接下来n行每行三个整数, ai bi ci,分别代表第i条线段的左端点ai,右端点bi(保证左端点<右端点)和价值ci。
输出描述
Output Description
输出能够获得的最大价值
样例输入
Sample Input
3
1 2 1
2 3 2
1 3 4
样例输出
Sample Output
4
线段覆盖总共有五道题,其中线段覆盖4最为典型,原因有二:
1.时间会超时,需要结合二分,时间复杂度O(nlogn);
2.边有权值;
做法和大体dp相同,先固定一个值的顺序,再通过比较第二个值来确定结果,只不过在比较第二个值的时候变成了使用二分比较。
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
struct l{
int s, e;
long long v;
}a[1000005];
long long mx[1000005];
bool cmp(l x, l y)
{
if(x.e == y.e)
return x.s < y.s;
return x.e < y.e;
}
long long max(long long x, long long y)
{
return x > y ? x : y;
}
int main()
{
int n, k;
long long p;
cin >> n;
for(int i = 1; i <= n; i++)
{
scanf("%d%d%lld", &a[i].s, &a[i].e, &a[i].v);
}
sort(a + 1, a + n + 1, cmp);
long long ans = a[1].v;
for(int i = 1; i <= n; i++)
{
int Max = 0;
int l = 1;
int r = i - 1;
while(l <= r)
{
int mid = (l + r) / 2;
if(a[mid].e > a[i].s)
{
r = mid - 1;
}
else
l = mid + 1;
}
a[i].v += mx[r];
if(ans < a[i].v)
ans = a[i].v;
mx[i] = max(mx[i - 1], a[i].v);
}
cout << ans << endl;
return 0;
}