Milking Cows

Problem:

 

Milking Cows

Three farmers rise at 5 am each morning and head for the barn to milk three cows. The first farmer begins milking his cow at time 300 (measured in seconds after 5 am) and ends at time 1000. The second farmer begins at time 700 and ends at time 1200. The third farmer begins at time 1500 and ends at time 2100. The longest continuous time during which at least one farmer was milking a cow was 900 seconds (from 300 to 1200). The longest time no milking was done, between the beginning and the ending of all milking, was 300 seconds (1500 minus 1200).

Your job is to write a program that will examine a list of beginning and ending times for N (1 <= N <= 5000) farmers milking N cows and compute (in seconds):

  • The longest time interval at least one cow was milked.
  • The longest time interval (after milking starts) during which no cows were being milked.

PROGRAM NAME: milk2

INPUT FORMAT

Line 1: The single integer
Lines 2..N+1: Two non-negative integers less than 1000000, the starting and ending time in seconds after 0500

SAMPLE INPUT (file milk2.in)

3
300 1000
700 1200
1500 2100

OUTPUT FORMAT

A single line with two integers that represent the longest continuous time of milking and the longest idle time.

SAMPLE OUTPUT (file milk2.out)

900 300


My Answer:

 
<think>题目:Balanced Lineup 问题描述:有N头牛,每头牛有一个身高。有Q个查询,每个查询给出一个区间[A, B],要求输出该区间内最高牛的身高和最低牛的身高之差。 由于N最大为50,000,Q最大为200,000,我们不可能对每个查询都遍历区间(那将是O(N*Q)的复杂度,会超时)。 因此,我们需要一种高效的数据结构来支持区间最大/最小值查询。线段树(Segment Tree)或稀疏表(Sparse Table)是合适的选择。 这里我们使用线段树,因为线段树支持更新操作(虽然本题没有更新,但线段树是一个通用解法),而且空间复杂度为O(N),构建时间为O(N),每个查询时间为O(logN)。 步骤: 1. 构建线段树,每个节点存储对应区间的最大值和最小值。 2. 对于每个查询,查询区间的最大值和最小值,然后输出差值。 线段树节点设计: struct Node { int l, r; int max_val, min_val; } 构建树:递归构建,每个节点的最大值和最小值由左右子树得到。 查询:对于给定的区间[A, B],返回一个包含最大值和最小值的结构,然后计算差值。 注意:数组下标从0开始,但题目输入中的牛编号是从1开始的,我们需要调整查询区间(减1)。 由于查询只有200,000次,每次查询O(logN)总时间为O(Q logN),在可接受范围内。 代码实现: 我们将实现一个线段树,支持: build_tree: 构建线段树 query: 查询区间的最小值和最大值 注意:线段树数组通常开4倍空间。 样例验证: 输入:N=6, Q=3, 高度=[1,7,3,4,2,5] 查询:[1,5] -> [0,4]:最大值7,最小值1 -> 6 [4,6] -> [3,5]:最大值5,最小值2 -> 3 [2,2] -> [1,1]:最大值7,最小值7 -> 0 实现: </think> ### 解决方案:使用线段树高效查询区间最值差 #### 问题分析 给定N头牛的身高序列和Q个区间查询,每个查询要求计算区间内最高身高和最低身高的差值。由于N最大为50,000,Q最大为200,000,暴力解法(每个查询遍历区间)的时间复杂度为O(NQ)会超时。 采用线段树可以在O(N)预处理时间和O(logN)单次查询时间内解决: 1. **线段树结构**:每个节点存储区间的最小值和最大值 2. **查询处理**:对每个区间查询,返回其最小值和最大值并计算差值 #### 完整代码实现(C++) ```cpp #include <iostream> #include <vector> #include <climits> #include <algorithm> using namespace std; struct Node { int min_val; int max_val; }; class SegmentTree { private: vector<Node> tree; vector<int> data; int n; void build_tree(int node, int start, int end) { if (start == end) { tree[node] = { data[start], data[start] }; } else { int mid = (start + end) / 2; build_tree(2 * node + 1, start, mid); // 左子树 build_tree(2 * node + 2, mid + 1, end); // 右子树 tree[node].min_val = min(tree[2 * node + 1].min_val, tree[2 * node + 2].min_val); tree[node].max_val = max(tree[2 * node + 1].max_val, tree[2 * node + 2].max_val); } } Node query_range(int node, int start, int end, int l, int r) { if (r < start || end < l) { return { INT_MAX, INT_MIN }; // 区间不重叠,返回无效值 } if (l <= start && end <= r) { return tree[node]; // 当前区间完全包含在查询区间内 } int mid = (start + end) / 2; Node left_res = query_range(2 * node + 1, start, mid, l, r); Node right_res = query_range(2 * node + 2, mid + 1, end, l, r); return { min(left_res.min_val, right_res.min_val), max(left_res.max_val, right_res.max_val) }; } public: SegmentTree(const vector<int>& arr) : data(arr), n(arr.size()) { tree.resize(4 * n); build_tree(0, 0, n-1); } int query(int l, int r) { Node res = query_range(0, 0, n-1, l, r); return res.max_val - res.min_val; } }; int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int N, Q; cin >> N >> Q; vector<int> heights(N); for (int i = 0; i < N; i++) { cin >> heights[i]; } SegmentTree st(heights); for (int i = 0; i < Q; i++) { int A, B; cin >> A >> B; // 输入区间是从1开始,转换为0-based索引 [A-1, B-1] cout << st.query(A-1, B-1) << '\n'; } return 0; } ``` #### 代码详解 1. **线段树结构** - `Node`结构体:存储区间的最小值`min_val`和最大值`max_val` - 树数组`tree`:大小设为4倍原数组长度(确保完全二叉树存储) 2. **建树过程(O(N))** ```cpp void build_tree(int node, int start, int end) { if (start == end) { // 叶子节点 tree[node] = {data[start], data[start]}; } else { int mid = (start+end)/2; build_tree(2*node+1, start, mid); // 递归构建左子树 build_tree(2*node+2, mid+1, end); // 递归构建右子树 // 合并子树信息 tree[node].min_val = min(left.min, right.min); tree[node].max_val = max(left.max, right.max); } } ``` 3. **区间查询(O(logN))** ```cpp Node query_range(int node, int start, int end, int l, int r) { // 当前区间与查询区间无重叠 if (r < start || end < l) return {INT_MAX, INT_MIN}; // 当前区间完全包含在查询区间内 if (l <= start && end <= r) return tree[node]; // 部分重叠,递归查询子树 int mid = (start+end)/2; Node left = query_range(2*node+1, start, mid, l, r); Node right = query_range(2*node+2, mid+1, end, l, r); return { min(left.min_val, right.min_val), max(left.max_val, right.max_val) }; } ``` 4. **主流程** - 读取牛的数量`N`和查询数量`Q` - 读取牛的身高数据 - 构建线段树(预处理) - 对每个查询`[A,B]`: - 转换为0-based索引`[A-1, B-1]` - 调用`query()`获取区间最值差并输出 #### 复杂度分析 - **时间复杂度**: - 建树:O(N) - 单次查询:O(logN) - 总时间:O(N + QlogN) ≈ 50,000 + 200,000×log₂(50,000) ≈ 3.6×10⁶ - **空间复杂度**:O(N)(4倍数组空间 ≈ 200,000) #### 优化讨论 1. **稀疏表替代方案**: - 适用场景:静态数组(无更新操作) - 优势:O(1)查询,O(NlogN)预处理 - 劣势:空间复杂度O(NlogN) 2. **线段树优化**: - 非递归实现 - 内存池分配 - 查询剪枝优化 样例验证: ```text 输入: 6 3 1 7 3 4 2 5 1 5 4 6 2 2 输出: 6 // [1,5]: max=7, min=1 → 6 3 // [4,6]: max=5, min=2 → 3 0 // [2,2]: max=min=7 → 0 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值