P2082 区间覆盖(加强版)

P2082 区间覆盖(加强版)

题目

已知有 \(N\) 个区间,每个区间的范围是 \([s_i,t_i]\),请求出区间覆盖后的总长。

输入

第一行一个正整数 \(N\),表示区间个数。

接下来 \(N\) 行,每行两个正整数,表示 \(s_i\)\(t_i\)

输出

共一行,一个正整数,为覆盖后的区间总长。

样例

输入

3
1 100000
200001 1000000
100000000 100000001

输出

900002

提示

对于 \(40 \%\) 的数据,\(N \le 1000\)\(1 \le s_i < t_i \le 10000\)

对于 \(100 \%\) 的数据 ,\(N \le 10^5\)\(1 \le s_i < t_i \le 10^{17}\)


思路

在分析这道题之前先学习一下“区间合并”的问题:数轴上有 \(n\) 个闭区间 \(\lbrack a_i,b_i \rbrack\),尽量选择少的区间覆盖一个指定的区间 \(\lbrack s,t \rbrack\)

这是“区间覆盖问题”,分析:将区间左端点从小到大排序,如果第一个区间的左端点 \(a_1\) 大于 \(s\),无解。否则依次枚举起点 \(a_i\) 小于 \(s\) 的区间,记录 \(b_i\) 的最大值。如上图,区间 \(1\)、区间 \(2\)、区间 \(3\) 的左端点均小于 \(s\),其中右端点 \(b_2\) 为最大值,记录下来。如果 \(b_2\) 依然小于 \(s\) 则无解,否则 \(s\) 被更新成 \(b_2\),答案累加 \(1\)。按照类似的方式继续判断区间 \(4\)、区间 \(5\)

按照上述方法,排序后从左到右依次枚举区间,复杂度为 \(O(n)\)

回归本题,同样是一道“区间合并”的问题,看到区间问题容易想到贪心的方法,将区间左端点 \(L\) 排序,然后从左到右维护,\(R\) 表示已经贪心到的最右端的边界,如果当前的右边界大于等于 \(R\) 就加上不重复覆盖的区间长度,同时更新 \(R\)


代码

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 1e5 + 5;
long long n, R, ans;

struct Range
{
	long long l, r;
	bool operator < (const Range v) const
	{
		return l < v.l;
	}
} a[MAXN];

int main()
{
	scanf("%d", &n);
	for (long long i = 1; i <= n; i ++ )
		scanf("%ld %ld", &a[i].l, &a[i].r);
	sort(a + 1, a + n + 1);
	for (long long i = 1; i <= n; i ++ )
	{
		if (R <= a[i].r)
		{
			ans += a[i].r - max(R, a[i].l) + 1;
			R = a[i].r + 1;
		}
	}
	printf("%ld", ans);
	return 0;
}
posted @ 2025-01-09 22:41  IronMan_PZX  阅读(79)  评论(0)    收藏  举报
Title