题目大意
给定 n 条线段 [Li,Ri],线段端点都在 1∼m 的范围内。需要统计满足题意的区间数量(等价于对每个左端点 l,能延伸到的最大右端点受右侧最小的 R 约束),并输出总数。
AC代码
主要思路是一个点所能到达的最大边界取决于它的minR,也即在它右边的最小右边界
可以看到minR的统计过程是这样的
1 2 3 4 5 6 7 8 9 10 11
| for(int _=1;_<=n;_++) { ll l,r; cin>>l>>r; minR[l]=min(minR[l],r); } ll currMin=m+1; for(int i=m;i>=1;--i) { currMin=min(currMin,minR[i]); minR[i]=currMin; }
|
可以证明在 【Li,Ri】,比Li还小的地方 l(包含Li)的【l,r】区间包含Ri,必然导致【l,r】包含【Li,Ri】
所以比Li更小的地方应该将Ri考虑在minR的取值中
比如说minR[1]==4 他的答案怎么统计那?
可以看到一共有三种区间([1,3],[1,2],[1,1])即区间长度之和即为答案([1,4])
然后还有一些离线化的优化方法,注释里写的很清楚
AC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include <iostream> #include <cstring> #include <algorithm> #include <deque> #include <queue> #include <vector> #include <set> #include <cmath> #include <bitset>
using namespace std; typedef long long ll; const ll N=2e5+10; ll n,m,cnt,minR[N],ans;
void debug() { for(int i=1;i<=m;++i) { cout<<minR[i]<<" "; } cout<<endl; } int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin>>n>>m; for(int i=1;i<=m;i++) { minR[i]=m+1; } for(int _=1;_<=n;_++) { ll l,r; cin>>l>>r; minR[l]=min(minR[l],r); } ll currMin=m+1; for(int i=m;i>=1;--i) { currMin=min(currMin,minR[i]); minR[i]=currMin; } ans=0; for(int i=1;i<=m;++i) { ans+=minR[i]-i; } cout<<ans<<endl; }
|
心路历程(WA,TLE,MLE……)
一次提交过的,之前的代码样例都过不了就不放在这里了