题解:洛谷 P11453 Deforestation
【题目来源】
洛谷:P11453 [USACO24DEC] Deforestation S - 洛谷
【题目描述】
Farmer John 正在扩大他的农场!他已经找到了完美的位置——红黑森林,由数轴上的 \(N\) 棵树(\(1≤N≤10^5\))组成,第 \(i\) 棵树位于位置 \(x_i\)(\(−10^9≤x_i≤10^9\))。
环境保护法限制了 Farmer John 可以砍伐哪些树来为他的农场腾出空间。有 \(K\) 个限制(\(1≤K≤10^5\)),规定在线段 \([l_i,r_i]\)(包含端点)中必须始终至少存在 \(t_i\) 棵树(\(−10^9≤l_i,r_i≤10^9\))。输入保证红黑森林初始时满足这些限制。
Farmer John 想要他的农场尽可能大。请帮助他计算他可以砍伐的树的最大数量,同时仍然满足所有限制!
【输入】
每个测试点包含 \(T\)(\(1≤T≤10\))个独立的测试用例。输入保证一个测试点中的所有 \(N\) 之和以及 \(K\) 之和均不超过 \(3⋅10^5\)。
输入的第一行包含 \(T\)。每个测试用例的格式如下:
- 第一行包含整数 \(N\) 和 \(K\)。
- 下一行包含 \(N\) 个整数 \(x_1,\cdots,x_N\)。
- 以下 \(K\) 行,每行包含三个空格分隔的整数 \(l_i\),\(r_i\) 和 \(t_i\)。
【输出】
对于每个测试用例,输出一行,包含一个整数,表示 Farmer John 可以砍伐的树的最大数量。
【输入样例】
3
7 1
8 4 10 1 2 6 7
2 9 3
7 2
8 4 10 1 2 6 7
2 9 3
1 10 1
7 2
8 4 10 1 2 6 7
2 9 3
1 10 4
【输出样例】
4
4
3
【核心思想】
-
问题分析:给定数轴上 \(N\) 棵树的位置 \(x_i\) 和 \(K\) 个区间约束 \([l_i, r_i]\),要求每个区间内至少保留 \(t_i\) 棵树。求最多可砍伐的树的数量。本质上是差分约束 + 最长路问题:设 \(S_i\) 为排序后前 \(i\) 个点中保留的树的数量,将约束转化为不等式组,用 SPFA 求最长路得到 \(S_n\) 的最大值,最终答案为 \(N - S_n\)。
-
算法选择:
- 差分约束建模:将问题转化为 \(S_i\) 的约束不等式系统,用图论方法求解
- SPFA 求最长路:差分约束的解对应图中的最长路径,用 SPFA 处理可能存在负权边的情况
-
关键步骤:
- 读取数据:读入 \(T\) 组测试数据,每组读入 \(N, K\) 和 \(N\) 个坐标 \(x_i\)
- 排序坐标:
sort(x[1..N]),将离散坐标排序后转化为前缀问题 - 建图:
- 基础约束(\(i = 1\) 到 \(N\)):
- \(S_i - S_{i-1} \leq 1\)(最多保留 \(1\) 棵):建边 \(i \to i-1\),权值 \(-1\)
- \(S_i \geq S_{i-1}\)(单调不减):建边 \(i-1 \to i\),权值 \(0\)
- 区间约束:对每个 \([l, r, t]\):
- 用
lower_bound和upper_bound找到排序后对应的位置区间 \([L, R]\) - 约束 \(S_R - S_{L-1} \geq t\):建边 \(L-1 \to R\),权值 \(t\)
- 用
- 基础约束(\(i = 1\) 到 \(N\)):
- SPFA 求最长路:从顶点 \(0\) 出发,求到所有点的最长距离 \(dist[i]\)
- 输出:\(N - dist[N]\)(最多砍伐数 = 总数 \(-\) 最少保留数)
-
时间/空间复杂度:
- 时间复杂度:\(O(T \cdot (N + K) \log N)\),排序 \(O(N \log N)\),SPFA 平均 \(O(N + K)\)
- 空间复杂度:\(O(N + K)\),邻接表存储
-
差分约束的核心思想:
- 前缀和建模:\(S_i\) 表示前 \(i\) 个点中保留的数量,将"区间至少保留 \(t\) 棵"转化为 \(S_R - S_{L-1} \geq t\)
- 不等式转图论:\(x_j - x_i \geq c\) 对应边 \(i \to j\) 权值 \(c\),求最长路;\(x_j - x_i \leq c\) 对应边 \(j \to i\) 权值 \(-c\)
- 单调性约束:\(0 \leq S_i - S_{i-1} \leq 1\) 保证每个点要么保留要么砍伐,且前缀和不减
- 答案转换:差分约束求的是 \(S_n\) 的最大值(最多保留),题目要求最多砍伐,故为 \(N - S_n\)
- 适用于区间覆盖、资源分配、前缀约束类问题
【算法标签】
普及+ #差分约束
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 100005, M = N * 3; // 最大顶点数和边数
int T, n, k; // T: 测试用例数, n: 点数, k: 区间约束数
int x[N]; // 点坐标数组
int h[N], e[M], ne[M], w[M], idx; // 链式前向星存储图
int dist[N]; // 最长距离数组
bool st[N]; // 标记顶点是否在队列中
/**
* 添加有向边
* @param a 起点
* @param b 终点
* @param c 权重
*/
void add(int a, int b, int c)
{
e[idx] = b; // 边指向的顶点
w[idx] = c; // 边的权重
ne[idx] = h[a]; // 指向原链表头
h[a] = idx++; // 更新头指针
}
/**
* SPFA算法求最长路径
* 从顶点0开始,计算到所有顶点的最长路径
*/
void spfa()
{
// 初始化距离为负无穷
memset(dist, -0x3f, sizeof(dist));
memset(st, 0, sizeof(st));
queue<int> q; // SPFA队列
q.push(0); // 起点入队
st[0] = true; // 标记在队列中
dist[0] = 0; // 起点距离为0
while (!q.empty())
{
int t = q.front(); // 取出队首
q.pop();
st[t] = false; // 标记不在队列中
// 遍历t的所有邻接边
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]; // 更新最长距离
// 如果j不在队列中,入队
if (!st[j])
{
q.push(j);
st[j] = true;
}
}
}
}
}
int main()
{
// 输入测试用例数
cin >> T;
while (T--)
{
// 输入点数和区间约束数
cin >> n >> k;
// 初始化邻接表
memset(h, -1, sizeof(h));
idx = 0;
// 输入n个点的坐标
for (int i = 1; i <= n; i++)
{
cin >> x[i];
}
// 对点坐标排序
sort(x + 1, x + n + 1);
// 添加基础约束边
// 顶点编号0~n,表示排序后的前缀
for (int i = 1; i <= n; i++)
{
// 约束1: S_i - S_{i-1} ≤ 1
// 即: S_{i-1} - S_i ≥ -1
// 建边: i → i-1,权重-1
add(i, i - 1, -1);
// 约束2: S_i ≥ S_{i-1}
// 即: S_i - S_{i-1} ≥ 0
// 建边: i-1 → i,权重0
add(i - 1, i, 0);
}
// 处理k个区间约束
while (k--)
{
int l, r, t;
cin >> l >> r >> t;
int len = r - l + 1; // 区间长度(未使用)
// 在排序后的点数组中查找l和r对应的位置
// lower_bound: 找到第一个≥l的点
l = lower_bound(x + 1, x + n + 1, l) - x;
// upper_bound: 找到第一个>r的点,然后-1得到最后一个≤r的点
r = upper_bound(x + 1, x + n + 1, r) - x - 1;
// 添加区间约束边
// 如果l≤r,表示有满足条件的点
// 约束: S_r - S_{l-1} ≥ t
// 建边: l-1 → r,权重t
add(l - 1, r, t);
}
// 执行SPFA算法求最长路径
spfa();
/**
* 输出结果
* 设S_i表示前i个点中被选中的点数
* 我们求的是S_n的最大值
* 但题目要求的是不被选中的点数
* 所以结果为: n - S_n
*/
cout << n - dist[n] << endl;
}
return 0;
}
【运行结果】
3
7 1
8 4 10 1 2 6 7
2 9 3
4
7 2
8 4 10 1 2 6 7
2 9 3
1 10 1
4
7 2
8 4 10 1 2 6 7
2 9 3
1 10 4
3
浙公网安备 33010602011771号