线段覆盖
【题目描述】
在一个数轴上有n(n <= 1000000)条线段,每条线段的两端可用整数坐标表示,坐标范围为[0,1018],每条线段都有一个价值Ci(0 <= Ci <= 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; }