题目链接:
-
3 2 2 5 4 10 14 18 1 3 8 15
样例输出
-
8
描述
给定两个区间集合 A 和 B,其中集合 A 包含 N 个区间[ A1, A2 ], [ A3, A4 ], ..., [ A2N-1, A2N ],集合 B 包含 M 个区间[ B1, B2 ], [ B3, B4 ], ..., [ B2M-1, B2M ]。求 A - B 的长度。
例如对于 A = {[2, 5], [4, 10], [14, 18]}, B = {[1, 3], [8, 15]}, A - B = {(3, 8), (15, 18]},长度为8。
输入
第一行:包含两个整数 N 和 M (1 ≤ N, M ≤ 100000)。
第二行:包含 2N 个整数 A1, A2, ..., A2N (1 ≤ Ai ≤ 100000000)。
第三行:包含 2M 个整数 B1, B2, ..., B2M (1 ≤= Bi ≤ 100000000)。
输出
一个整数,代表 A - B 的长度。
一般区间问题:
对于由2N个点所构成的N个区间,用绿色表示区间左端点,蓝色表示右端点。将所有的点放入容器中并按升序排序,设置计数变量cnt标记当前位置由几个区间所包含,然后从小到大依次遍历2N个点,如果是左端点则cnt++,右端点则cnt--。计算出每一段所属区间的个数(cnt)就可以做很多事情,比如要求多个区间并集的长度,只要求出所有cnt大于0的线段的长度和即可。另外,还可以求出被覆盖最多次的线段(cnt的最大值)等等。值得注意的是,对于重合的点的处理可能需要仔细考虑,而本题中无需考虑,可将重合的点看成多个重叠的长度为0的线段,并不影响我们的计算结果。
回到本题,要计算A - B的长度,就要先考虑好哪些点是属于A - B这个集合的,存在什么样的特征。我们可以将A, B集合中的左右端点分别用四种标记来标识,放到容器中然后从小到大排序。设置变量cnta与cntb分别对集合A与集合B进行计数,即当前点为集合A的左端点时cnta++,为集合A右端点时,cnta--。集合b中的点同理。显然,A - B等价于所有满足cnta > 0且cntb=0的线段。
参考代码如下:
/***********************
[Hihocoder] 第152周 - 区间求差
Author:ZhengJianlong
Time:2017/6/01 15:04
language:C++
http://blog.youkuaiyun.com/z8596300
***********************/
#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int a[200005]={0}, b[200005]={0};
bool Compare(pair<int, int> p1, pair<int, int> p2)
{
if(p1.second != p2.second)
return p1.second < p2.second;
else
return p1.first <p2.first;
}
int main()
{
int N, M;
vector <pair <int, int>> pset;
// freopen("in.txt", "r", stdin);
cin>>N>>M;
for(int i=0; i<2*N; i++)
cin>>a[i];
for(int i=0; i<2*M; i++)
cin>>b[i];
for(int i=0; i<2*N; i++)
{
if(i%2 == 0)
pset.push_back(make_pair(0, a[i]));
else
pset.push_back(make_pair(1, a[i]));
}
for(int i=0; i<2*M; i++)
{
if(i%2 == 0)
pset.push_back(make_pair(2, b[i]));
else
pset.push_back(make_pair(3, b[i]));
}
sort(pset.begin(), pset.end(), Compare);
int cnta=0, cntb=0, ans=0;
for(int i=0; i<pset.size()-1; i++)
{
pair<int, int> cpair = pset[i];
switch(cpair.first)
{
case 0:
cnta++;
break;
case 1:
cnta--;
break;
case 2:
cntb++;
break;
case 3:
cntb--;
break;
default:
break;
}
if(cnta>0 && cntb==0)
ans += (pset[i+1].second - pset[i].second);
}
cout<<ans;
return 0;
}