差分约束
题目描述
在一条长度为 \(L = 5 \times 10^4\) 的线性轨道上,有 \(n\) 次经过一个物体。每个监测装置视为一个点,当轨道上有物体经过时会被触发。现在需要在轨道上部署若干检测装置(每个装置占据一个整数点位置),要求对于每个监测区域 \(i\),当有物体从 \(a_i\) 移动到 \(b_i\) 时,沿途至少触发 \(c_i\) 个检测装置(\(a_i\) 和 \(b_i\) 也算沿途)。问最少需要部署多少个检测装置才能满足所有监测区域的触发需求?
输入格式
第一行一个整数 \(n\),表示物体个数;
以下 \(n\) 行每行描述这些物体,第 \(i+1\) 行三个整数 \(a_i,b_i,c_i\),由空格隔开。
输出格式
一行,输出满足要求的最少检测装置个数。
样例数据
输入数据 1
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
数据范围
对于 \(100\%\) 的数据,对于全部数据,\(1\le n\le 5\times 10^4,0\le a_i\le b_i\le 5\times 10^4,1\le c_i\le b_i-a_i+1\)。
// 差分约束 + SPFA 解法思路:
// 1. 定义前缀变量 S[i] 表示在轨道点 1..i 上放置的检测装置总数,目标求 S[L]
// 2. 对于每个监测区间 [a,b] 需至少 c 个装置:
// S[b] - S[a-1] >= c ⇒ 边 (u=a-1) -> (v=b), 权重 w=c
// 3. 每个点至多放一个装置:0 <= S[i] - S[i-1] <= 1,拆为两条约束:
// S[i] - S[i-1] >= 0 ⇒ 边 (i-1) -> i, w=0
// S[i-1] - S[i] >= -1 ⇒ 边 i -> (i-1), w=-1
// 4. 将所有约束建成有向图,对 S[i] 做“最长路”松弛:
// 初始化 dist[] = -INF, dist[0] = 0
// 对边 u->v,w 做 if(dist[v] < dist[u] + w) dist[v] = dist[u] + w
// 5. SPFA 实现最长路松弛,最终 dist[L] 即为所求最小满足解
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
// 轨道最大长度 L,节点编号从 S_0 到 S_L 共 L+1 个
const int L = 50000;
const ll NEG_INF = -(1LL<<60); // 用于初始化最小值
// 边结构:从 u -> v ,权重 w 表示 S[v] >= S[u] + w
struct Edge {
int to;
ll w;
};
// 邻接表存图:节点 0..L
vector<Edge> adj[L+1];
// 添加一条差分约束边:S[v] >= S[u] + w
void add_edge(int u, int v, ll w) {
adj[u].push_back({v, w});
}
// SPFA 求解差分约束中的“最长路”问题
ll spfa() {
vector<ll> dist(L+1, NEG_INF);
vector<bool> inq(L+1, false);
deque<int> q;
// 初始化:令 S[0] = 0,其他 S[i] 从 -INF 开始
dist[0] = 0;
q.push_back(0);
inq[0] = true;
while (!q.empty()) {
int u = q.front();
q.pop_front();
inq[u] = false;
for (auto &e : adj[u]) {
int v = e.to;
ll w = e.w;
if (dist[v] < dist[u] + w) {
dist[v] = dist[u] + w;
if (!inq[v]) {
inq[v] = true;
q.push_back(v);
}
}
}
}
// 返回 S[L]
return dist[L];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
// 读入 n 条区间约束 [a, b, c]
for (int i = 0; i < n; i++) {
int a, b, c;
cin >> a >> b >> c;
int u = max(0, a - 1);
int v = b;
add_edge(u, v, c);
}
// 相邻点差分约束
for (int i = 1; i <= L; i++) {
add_edge(i-1, i, 0);
add_edge(i, i-1, -1);
}
ll ans = spfa();
cout << ans << "\n";
return 0;
}
练习题:
https://www.luogu.com.cn/problem/P1645
学习参考资料:
https://oi-wiki.org/graph/diff-constraints/
https://www.cnblogs.com/TanJI-C/p/15162547.html

浙公网安备 33010602011771号