某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。
由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
输入描述:
第一行有两个整数:L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。
输出描述:
包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。
示例1
输入
500 3
150 300
100 200
470 471
输出
298
备注:
对于20%的数据,区域之间没有重合的部分;
对于其它的数据,区域之间有重合的情况。
题解一:直接标记法(若数据范围大了,这种做法会超时)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <sstream>
#include <stack>
#include <algorithm>
using namespace std;
typedef long long ll;
#define maxn 1000005
#define mod 7654321
#define NIL -1
const int T = 1e6;
int L,N;
int arr[T];
void solve(int a,int b)
{
for(int i=a;i<=b;i++)
{
arr[i] = 1;
}
}
int main()
{
cin>>L>>N;
int a,b;
while(N--)
{
cin>>a>>b;
solve(a,b);
}
int res = 0;
for(int i=0;i<=L;i++)
if(arr[i])
res++;
cout<<L - res + 1<<endl;
return 0;
}
题解二:区间合并(适用于大数据)
区间合并:
算法流程:
1、先按照所有区间左端点进行从小到大排序
2、从前往后扫描每个区间,重复就合并
3、断开就进行重新分配起终点
注意:
1、由于起始位置已经设为第一个区间,所以循环从第二个区间开始
2、扫描完记得在循环外加上最后一个子区间,因为最后一个区间结束没有进行累加
参考代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <sstream>
#include <stack>
#include <algorithm>
using namespace std;
typedef long long ll;
#define maxn 1000005
#define mod 7654321
#define NIL -1
const int N = 1e6;
pair<int,int> p[N];
int main()
{
int L,M;
cin>>L>>M;
for(int i = 0;i < M;i++)
{
cin>>p[i].first>>p[i].second;
}
//按左端点排序
sort(p,p+M);
int st = p[0].first,ed = p[0].second;
int num = 0;
//从第二段开始遍历
for(int i = 1;i < M;i++)
{
if(p[i].first < ed)//若重合
{
ed = max(ed,p[i].second);
}
else//若断开
{
//存储当前区间长度
num += ed - st +1;
//更新起终点为当前节点
st = p[i].first;
ed = p[i].second;
}
}
//加上最后一段区间
num += ed - st +1;
cout<<L - num + 1<<endl;
return 0;
}