这两题一样就放一起写了。
无非就是值周的数据范围大一些。。
校门外的树可以直接暴力就ok。
值周的话。
考虑把区间修改变成区间端点修改,即差分,m次结束后进行一次前缀和。然后统计没有被标记过的即可。
这里顺便提一下扩展的内容,就是说L很大,数组开不下,m的大小还是不变。
这里我们不能差分了,应该数组太大了开不下。那么我们可以反过来求,求有多少个被覆盖的,总长度减去被覆盖的就是答案。
那么问题就是怎么求被覆盖的点。
对m个段进行排序,以左端点升序。
我们维护一个当前的最大的右端点r,为什么?因为区间的点可能会被多次覆盖。
所以每到一个新的区间段,首先看这个区间的左端点是不是大于前面维护的最大的右端点r,是的话,说明当前区间段不和前面的覆盖,那么自然要加上当前段的区间长度,更新右端点。
如果当前段的左端点小于前面维护的右端点最大值r呢?继续看当前段的右端点是不是大于r,是的话多覆盖的区间就是当前右端点-r,并且更新r即可。
差分、前缀和
#include<bits/stdc++.h>
using namespace std;
int a[100000005];
int main(){
ios::sync_with_stdio(0);
int n,m;cin>>n>>m;
while(m--){
int l,r;cin>>l>>r;
a[l]++,a[r+1]--;
}
int ans=0;
for(int i=1;i<=n;i++){
a[i]+=a[i-1];
if(!a[i]) ans++;
}
cout<<ans+!a[0]<<endl;
return 0;
}排序维护右端点
#include<bits/stdc++.h>
using namespace std;
pair<int,int> c[1000005];
int main(){
int n,m;cin>>n>>m;
for(int i=1;i<=m;i++){
int l,r;cin>>l>>r;
c[i]={l,r};
}
sort(c+1,c+1+m);
int ans=0,r=0;
for(int i=1;i<=m;i++){
if(c[i].first>=r){
ans+=c[i].second-c[i].first+1;
r=c[i].second;
}
else if(c[i].second>=r){
ans+=c[i].second-r;
r=c[i].second;
}
}
cout<<n+1-ans;
return 0;
}
京公网安备 11010502036488号