区间合并
区间合并
区间合并(模板)
题目
给定 n 个闭区间 [ai; bi],其中i=1,2,...,n。任意两个相邻或相交的闭区间可以合并为一个闭区间。例如,[1;2] 和 [2;3] 可以合并为 [1;3],[1;3] 和 [2;4] 可以合并为 [1;4],但是[1;2] 和 [3;4] 不可以合并。
我们的任务是判断这些区间是否可以最终合并为一个闭区间,如果可以,将这个闭区间输出,否则输出no。
输入格式
第一行为一个整数n,3 ≤ n ≤ 50000。表示输入区间的数量。
之后n行,在第i行上(1 ≤ i ≤ n),为两个整数 ai 和 bi ,整数之间用一个空格分隔,表示区间 [ai; bi](其中 1 ≤ ai ≤ bi ≤ 10000)。
输入格式
输出一行,如果这些区间最终可以合并为一个闭区间,输出这个闭区间的左右边界,用单个空格隔开;否则输出 no。
输入样例1
5
5 6
1 5
10 10
6 9
8 10
输出样例1
1 10
题解
首先按左边元素最小进行排序,若相同则按照右边元素最小排序。
注意合并区间的边界问题
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define ppb pop_back
#define SZ(v) ((int)v.size())
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef double db;
using namespace std;
const int N = 1e6;
int _;
vector<pair<int, int>> a;
int n;
int cmp(const pair<int, int> &x, const pair<int, int> &y) {
if(x.fi == y.fi) {
return x.se < y.se; //左相同,则按右最小排列
}
return x.fi < y.fi; //按照左最下排列
}
void solve() {
cin >> n;
a.resize(n);
for(int i = 0; i < n; i++) {
cin >> a[i].fi >> a[i].se;
}
sort(a.begin(), a.end(), cmp);
int l = a[0].fi, r = a[0].se;
for(int i = 1; i < n; i++) {
if(a[i].fi > r) {
cout << "no\n";
return;
}
l = min(l, a[i].fi);
r = max(r, a[i].se);
}
cout << l << " " << r << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
_ = 1;
// cin >> _;
while(_--) {
solve();
}
return 0;
}
管道(区间合并例题)
题目
有一根长度为 len的横向的管道,该管道按照单位长度分为 len段,每一段的中央有一个可开关的阀门和一个检测水流的传感器。
求管道中每一段中间的传感器都检测到有水流的最早时间。
输入格式
输入的第一行包含两个整数 n, len,用一个空格分隔,分别表示会打开的阀门数和管道长度。
输出格式
输出一行包含一个整数表示答案。
数据范围
样例
输入样例1
3 10
1 1
6 5
10 2
输出样例1
5
题解
首先理解题意,把阀门取L点,而不是区间,只看点,所以
该题目需要用到二分+区间合并
该题目的区间合并需要注意的点是,两个点只要相邻即可合并,而不需要[1, 4], [4, 5],而是[1, 2], [3, 5]
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define ppb pop_back
#define SZ(v) ((int)v.size())
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef double db;
using namespace std;
const int N = 1e6;
int _;
vector<pair<ll, ll>> a;
ll b[N][2];
int n, len;
ll ans;
int cmp(const pair<ll, ll> &x, const pair<ll, ll> &y) {
if(x.fi == y.fi) {
return x.se < y.se;
}
return x.fi < y.fi;
}
bool check(ll x) { // 区间合并,主要判断当前的时间能否覆盖整个管道
a.clear();
for(int i = 0; i < n; i++) {
ll l = 0, r = 0;
if(x >= b[i][1]) {
l = b[i][0] - (x - b[i][1]);
l = max((ll)1, l);
r = b[i][0] + (x - b[i][1]);
r = min((ll)len, r);
a.push_back(make_pair(l, r));
}
}
sort(a.begin(), a.end(), cmp);
ll l = a[0].fi, r = a[0].se;
for(int i = 1; i < SZ(a); i++) {
if(a[i].fi - 1 > r) {
return 0;
}
l = min(l, a[i].fi);
r = max(r, a[i].se);
}
// cout << "l, r = ";
// cout << l << " " << r << '\n';
if(l == 1 && r == len) return true;
return false;
}
void solve() {
cin >> n >> len;
for(int i = 0; i < n; i++) {
cin >> b[i][0] >> b[i][1];
}
ll l = 1, r = 2*1e9;
while(l <= r) { // 二分一个时间点,注意设置区间初始值大小
ll mid = (l + r) / 2;
if(check(mid)) {
ans = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
cout << ans << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
_ = 1;
// cin >> _;
while(_--) {
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话