总说
本篇文章可能写的有点潦草(时间有点紧),仅供个人参考与复习,如有错误欢迎指出。
一、区间合并介绍
思路
常见类型是给我们n个区间,每个区间都符合性质,区间之间可能有交集,我们有时需要把相交区间合并,方便后续统计和计算。
题目链接:P1496 火烧赤壁 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
本题就是给了n个区间,让你统计总着火长度,由于总距离给的很大,如10^9,我们不能直接开一个数组,这里也用到了一些离散化的知识,把每个区间存下来,按左端点从小到大排序。由于区间之间可能有重复,所以想到了区间合并,合并时候每两个区间之间不会相交,之间遍历所有区间然后把区间长度相加即可。
代码模板
#include<iostream>
#include<cstring>
#include<algorithm>
#define x first //左边界
#define y second //右边界
using namespace std;
const int N = 2e4 + 10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef pair<int, int> PII;
int n;
PII a[N]; //定义一个pair类型数组,记录左右边界
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d %d", &a[i].x, &a[i].y);
sort(a + 1, a + n + 1); //区间合并前要先按左端点从小到大排序
int l = -INF, r = -INF; //初始左右边界
ll res = 0; //记录答案
for(int i = 1; i <= n; i++)
{
if(a[i].x > r) //不相交
{
res += r - l;
l = a[i].x;
r = a[i].y;
}
else
{
r = max(a[i].y, r);
if(i == n) //如果是最后一个了 直接结算
res += r - l;
}
}
printf("%lld", res);
return 0;
}
二、题目练习
2.1 记录合并区间
题目描述:
题目链接:P2434 [SDOI2005] 区间 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路分析:
基本上是板子题,这里需要在遍历的时候,如果此时2个区间不相交,就把上一个合并好的区间存起来。
代码模板:
#include<iostream>
#include<cstring>
#include<algorithm>
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 5e4 + 10;
int n, cnt;
PII a[N], res[N];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d %d", &a[i].x, &a[i].y);
sort(a + 1, a + n + 1);
int l = -1, r = -1;
for(int i = 1; i <= n; i++)
{
if(a[i].x > r)
{
if(r != -1)
res[++cnt] = {l, r}; //存下
l = a[i].x;
r = a[i].y;
}
else
r = max(r, a[i].y);
}
if(r != -1)
res[++cnt] = {l, r};
for(int i = 1; i <= cnt; i++)
printf("%d %d\n", res[i].x, res[i].y);
return 0;
}
2.2 合并过程更新最值
题目描述:
题目链接:1343. 挤牛奶 - AcWing题库
思路分析:
还是板子题,就是在合并过程中注意更新答案即可。
代码模板:
#include<iostream>
#include<cstring>
#include<algorithm>
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 5e3 + 10;
int n, res1, res2;
PII a[N];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d %d", &a[i].x, &a[i].y);
sort(a + 1, a + n + 1);
int l = -1, r = -1;
for(int i = 1; i <= n; i++)
{
res1 = max(res1, r - l); //单个区间
if(a[i].x > r)
{
if(r != -1)
{
res1 = max(res1, a[i].y - a[i].x);//合并的区间
res2 = max(res2, a[i].x - r);// 2个区间中间间隔
}
l = a[i].x;
r = a[i].y;
}
else
r = max(r, a[i].y);
}
printf("%d %d", max(res1, r - l), res2);
return 0;
}