给定 n 个区间 [ai,bi] 和 n 个整数 ci。
你需要构造一个整数集合 Z,使得 ∀i∈[1,n],Z 中满足 ai≤x≤bi 的整数 x不少于 ci 个。
求这样的整数集合 Z 最少包含多少个数。
输入格式
第一行包含整数 n。
接下来 n行,每行包含三个整数 ai,bi,ci。
输出格式
输出一个整数表示结果。
数据范围
1≤n≤50000,
0≤ai,bi≤50000,
1≤ci≤bi−ai+1
输入样例:
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
输出样例:
6
思路
/*
这一题是一定有解的,因为最坏的情况下我们可以把1~50000中的数据全部选上。
本次存在两种做法:(1)贪心;(2)差分约束。下面使用差分约束解决这个问题。
这里可以使用前缀和的思想求解,因为前缀和中S[0]=0,所有这里将ai,bi所在的区间范围加上一个1,区间范围变成了[1, 50001],这样并不影响最终的结果。
S[i]表示:前i个数中被选出数的个数。我们最终要求解的就是S50001的最小值,因此需要使用最长路径。
对于S,S需要满足如下条件:
(1)Si≥Si−1,1≤i≤50001;
(2)Si−Si−1≤1⟺Si−1≥Si−1;
(3)区间[a, b]中至少有c个数⟺Sb−Sa−1≥c⟺Sb≥Sa−1+c;
需要验证一下:从源点出发,是否一定可以走到所有的边。根据条件(1),从i-1可以走到i,因此从0可以走到1,从1可以走到2,......,因此存在这样的源点。
*/
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 10, M = 15e4 + 10;
int dist[N], st[N];
int h[N], e[M], ne[M], w[M], idx;
int n;
void add(int a, int b, int c)
{
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
void spfa()
{
memset(dist, -0x3f, sizeof(dist));
dist[0] = 0;
queue<int> qu;
qu.push(0);
st[0] = 1;
while (qu.size())
{
int t = qu.front();
qu.pop();
st[t] = 0;
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (dist[j] < dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
if (!st[j])
{
st[j] = 1;
qu.push(j);
}
}
}
}
}
int main()
{
scanf("%d", &n);
memset(h, -1, sizeof(h));
for (int i = 1; i < N; i++)
{
add(i - 1, i, 0);
add(i, i - 1, -1);
}
for (int i = 0; i < n; i++)
{
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
a++, b++;
add(a - 1, b, c);
}
spfa();
printf("%d\n", dist[50001]);
return 0;
}