little w and Segment Coverage 差分割槽間+字首和優化
阿新 • • 發佈:2018-12-23
連結: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;
}