链接:https://ac.nowcoder.com/acm/contest/297/C
来源:牛客网
题目描述
小w有m条线段,编号为1到m。
用这些线段覆盖数轴上的n个点,编号为1到n。
第i条线段覆盖数轴上的区间是L[i],R[i]。
覆盖的区间可能会有重叠,而且不保证m条线段一定能覆盖所有n个点。
现在小w不小心丢失了一条线段,请问丢失哪条线段,使数轴上没被覆盖到的点的个数尽可能少,请输出丢失的线段的编号和没被覆盖到的点的个数。如果有多条线段符合要求,请输出编号最大线段的编号(编号为1到m)。
输入描述:
第一行包括两个正整数n,m(1≤n,m≤10^5)。 接下来m行,每行包括两个正整数L[i],R[i](1≤L[i]≤R[i]≤n)。
输出描述:
输出一行,包括两个整数a b。 a表示丢失的线段的编号。 b表示丢失了第a条线段后,没被覆盖到的点的个数。
示例1
输入
5 3 1 3 4 5 3 4
输出
3 0
说明
若丢失第1条线段,1和2没被线段覆盖到。 若丢失第2条线段,5没被线段覆盖到。 若丢失第3条线段,所有点都被线段覆盖到了。
示例2
输入
6 2 1 2 4 5
输出
2 4
说明
若丢失第1条线段,1,2,3,6没被线段覆盖到。 若丢失第2条线段,3,4,5,6没被线段覆盖到。
****************************************************
前置技能: 差分区间优化区间操作 可用于树状数组和线段树
https://blog.csdn.net/yyx2000/article/details/65937481(我也属现学的)
差分区间修改操作是O(1)的,加上查询是O(n)的;用于直接修改加查询,不用建树了
当然若是边修改边查询 那还是用线段树吧
**********************************************************
题解 就是首先可以这样想 把那段1~n的数列看成都为0 ,在用差分区间处理就好了,覆盖就标记为1 ,在用得到前缀和数组去保存每个点之前的为被覆盖的点 ,哦对了还有一开始初始化后就没有被覆盖得点也先预处理上
有个问题就是这道题是刚开始多组区间初始化,所以差分区间合在一起写,sum前缀和数组处理的时候只用加上,被标记为1的点
,大于1的点,不用管,因为你删除一组区间后,这个点还在。
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
int l[maxn];
int r[maxn];
int a[maxn];//实质是标记数组
int sum[maxn];
int n,m;
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>l[i]>>r[i];//差分区间 可以假设初始每个点都是0 题中给出的每段区间都是把这段区间加1,标记上被覆盖
//题中给出的每段区间都是把这段区间加1,标记+1为是被覆盖
a[l[i]]+=1; ///差分思想 通过操作差分区间在O(1)内修改差分区间 在O(n)内修改原数组
a[r[i]+1]-=1;
}
for(int i=1;i<=n;i++){//还原回去每个点标记后的覆盖情况1为覆盖了一次 大于1 覆盖了多次
a[i]=a[i]+a[i-1]; //多个区间导致多个差分数组合并操作
}
int num=0;//原先就没有被覆盖的点
for(int i=1;i<=n;i++){
if(a[i]==0)
num++;
else if(a[i]==1)//标记被覆盖1次的点 覆盖多次不用管 不用放在sum和里
sum[i]=1;
}
// for(int i=1;i<=n;i++){
// cout<<sum[i]<<" ";
// }
// cout<<endl;
for(int i=1;i<=n;i++){
sum[i]+=sum[i-1];//前缀和
}
// cout<<num<<endl;
// for(int i=1;i<=n;i++){
// cout<<a[i]<<" ";
// }
// cout<<endl;
// for(int i=1;i<=n;i++){
// cout<<sum[i]<<" ";
// }
// cout<<endl;
int ans=inf;
int ant=0;
for(int i=m;i>=1;i--){ //逆序是因为若为被覆盖的点相同输出编号的的
int k=sum[r[i]]-sum[l[i]-1]+num;
// cout<<k<<endl;
if(k<ans){
ans=k;
ant=i;
}
}
cout<<ant<<" "<<ans<<endl;
return 0;
}