思路:
令dis[i]表示0到i这个区间内至少要选出dis[i]个数,那么对于每个[ai,bi],dis[bi] - dis[ai-1] >= ci,建ai-1 -> bi权值为ci的边。
同时隐含的一个条件是0 <= dis[i+1] - dis[i] <= 1:
dis[i+1] - dis[i] >= 0 可建i -> i+1边权为0的边
dis[i+1] - dis[i] <= 1 化为 dis[i] - dis[i+1] >= -1所以又可建i+1 -> i边权为-1的边
因为题目上的点可能为 0 ,所以is[bi] - dis[ai-1] >= ci中可能出现dis[-1]的情况,将所有点的数组下标右移一位即可
然后dis[0] = 0,直接求取最长路就行了,注意spfa求最长路dis初始化为-INF,还有更新比较改成 <。
代码:
#include <iostream>
#include <algorithm>
#include <iostream>
#include <string>
#include <stdio.h>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <math.h>
#include <climits>
#include <iomanip>
#include <queue>
#include <vector>
#define fastio ios::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL)
#define debug(a) cout << "debug : " << (#a) << " = " << a << endl
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 5e4 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
const int mod = 998244353;
int st = INF, ed = -1;
int dis[N];
bool vis[N];
int h[N], idx;
struct node
{
int r, w, nt;
} a[4 * N];
void add(int l, int r, int w)
{
a[idx] = {r, w, h[l]}, h[l] = idx++;
}
int spfa()
{
memset(dis, -INF, sizeof dis);
dis[st] = 0;
queue<int> q;
q.push(st);
vis[st] = true;
while (q.size())
{
int t = q.front();
q.pop();
vis[t] = false;
for (int i = h[t]; i != -1; i = a[i].nt)
{
int j = a[i].r, w = a[i].w;
if (dis[j] < dis[t] + w) //求最长路
{
dis[j] = dis[t] + w;
if (!vis[j])
{
q.push(j);
vis[j] = true;
}
}
}
}
return dis[ed];
}
int main()
{
memset(h, -1, sizeof h);
int n;
cin >> n;
while (n--)
{
int l, r, w;
scanf("%d%d%d", &l, &r, &w);
st = min(st, l), ed = max(ed, r);
add(l, r + 1, w);
}
ed++;
for (int i = st; i < ed; i++)
{
add(i, i + 1, 0);
add(i + 1, i, -1);
}
cout << spfa() << endl;
return 0;
}