5407.管道 (二分+区间合并)
原创 于 2024-01-03 14:27:26 发布 · 粉丝可见 · 483 阅读 · 11 · 12 · 本内容遵循CC 4.0 BY-SA版权协议 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 GEO检测 · 编辑 文章链接:https://blog.csdn.net/hacker_51/article/details/135352138
本题链接: 5407. 管道 - AcWing题库
题目:
样例:
cobol<br/>3 10<br/>1 1<br/>6 5<br/>10 2<br/>
思路: 根据题目意思,给出 n 个阀门,其中 管道有 len 段,随后 n 个阀门对应的位置在 L 点,并且当 S 时刻阀门的水会放开, 其中 放开后 水在 $$ T_{i} $$( $$ T_{i} $$≥ $$ S_{i} $$)时刻会使得从第 $$ L_{i} $$− ( $$ T_{i} $$− $$ S_{i} $$) 段到第 $$ L_{i} $$+ ( $$ T_{i} $$− $$ S_{i} $$) 段的传感器检测到水流。
问输出 全部段点感应到水流的 最早时间,这里 有可能出现同一时刻 水阀放水的过程,以及放水后 感应到的区域 部分同时感应,所以我们应该联想到 区间合并,判断区间是否覆盖完我们的全部管道即可,这里我们 枚举 时间,又因为数据范围较大,枚举时间肯定会 TLE,所以我们又应该联想到二分枚举时间,即可得到最优答案。
在这里需要注意的点是,第 $$ L_{i} $$− ( $$ T_{i} $$− $$ S_{i} $$) 段到第 $$ L_{i} $$+ ( $$ T_{i} $$− $$ S_{i} $$) 段的传感器检测到水流ta它的区间应该为:
L =
− (
−
) - 1 R =
+ (
−
)
这里 L 应该为 $$ L_{i} $$− ( $$ T_{i} $$− $$ S_{i} $$) - 1 ,是因为我们感应点应该包括 第 $$ L_{i} $$− ( $$ T_{i} $$− $$ S_{i} $$) 的点,所以我们区间的左端点 应该 - 1。
区间和并模板代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 inline void Merge (vector<PII>&p) { int sz = p.size (); if (sz <= 1 ) return ; sort (All (p)); vector<PII>tem; PII now = *p.begin (); for (int i = 1 ;i < sz;++i) { PII next = p[i]; if (now.y >= next.y) continue ; if (now.y >= next.x) now.y = next.y; else { tem.emplace_back (now); now = next; } } tem.emplace_back (now); p = tem; }
代码详解如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 #include <bits/stdc++.h> #define int long long #define endl '\n' #define x first #define y second #define All(x) x.begin(),x.end() #define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std;using PII = pair<int ,int >; int n,len; vector<PII>v; inline void Merge (vector<PII>&p) { int sz = p.size (); if (sz <= 1 ) return ; sort (All (p)); vector<PII>tem; PII now = *p.begin (); for (int i = 1 ;i < sz;++i) { PII next = p[i]; if (now.y >= next.y) continue ; if (now.y >= next.x) now.y = next.y; else { tem.emplace_back (now); now = next; } } tem.emplace_back (now); p = tem; } inline bool cheak (int t) { vector<PII>edge; for (int i = 0 ;i < n;++i) { PII now = v[i]; if (now.y > t)break ; int time = t - now.y; int l = now.x - time - 1 ; int r = now.x + time; edge.emplace_back (PII (l,r)); } Merge (edge); if (edge.size () != 1 ) return false ; else { PII have = *edge.begin (); if (have.x <= 0 && have.y >= len) return true ; else return false ; } } inline void solve () { int l = 0 ,r = -1 ; v.clear (); cin >> n >> len; for (int i = 0 ;i < n;++i) { int L,S; cin >> L >> S; r = max (S,r); v.emplace_back (PII (L,S)); } sort (All (v),[](const PII&a,const PII&b) { return a.y < b.y; }); r <<= 1 ; while (l < r) { int mid = l + r >> 1 ; if (cheak (mid)) r = mid; else l = mid + 1 ; } cout << l << endl; } signed main () { int _t = 1 ; IOS; while (_t --) { solve (); } return 0 ; }
最后提交: