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;
}

                
            
        
浙公网安备 33010602011771号