给出n<=100000个已覆盖的区间[Li,Ri],Li,Ri<=1e9,求再覆盖m<=1e9个点如何使最长覆盖区间最大。
感谢KPM大爷的题解!!
首先把重复区间处理掉,剩下若干个不重区间。这采用类似于差分的“事件法”,左边+1,右边-1,>0的部分即是区间。
接下来,“求满足某个条件的最长区间”,twopointer!
注意<和<=的运用!代码中用的是左右闭区间,但实操发现处理成左闭右开区间更方便。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<algorithm> 5 #include<math.h> 6 //#include<iostream> 7 using namespace std; 8 9 int n,m; 10 #define maxn 100011 11 struct Line 12 { 13 int v,id; 14 bool operator < (const Line &b) const 15 {return id<b.id || (id==b.id && v<b.v);} 16 }l[maxn];int len; 17 struct Point 18 { 19 int l,r; 20 }nl[maxn];int ln; 21 int x,y; 22 #define LL long long 23 int main() 24 { 25 while (~scanf("%d%d",&n,&m)) 26 { 27 len=0; 28 for (int i=1;i<=n;i++) 29 { 30 scanf("%d%d",&x,&y); 31 l[++len].v=1;l[len].id=x; 32 l[++len].v=-1;l[len].id=y+1; 33 } 34 sort(l+1,l+1+len); 35 int now=0,L,R;ln=0; 36 for (int i=1;i<=len;i++) 37 { 38 now+=l[i].v; 39 if (now==1 && l[i].v==1) L=l[i].id; 40 else if (now==0) 41 { 42 R=l[i].id-1; 43 nl[++ln].l=L;nl[ln].r=R; 44 } 45 } 46 now=0,L=1,R=1; 47 LL ans=0; 48 nl[0].l=nl[0].r=0; 49 while (L<=ln && R<=ln) 50 { 51 while (R<=ln && now<=m) 52 { 53 ans=max(ans,(LL)((nl[R].r-nl[L].l+1)+m-now)); 54 R++; 55 if (R<=ln) now+=nl[R].l-nl[R-1].r-1; 56 } 57 L++; 58 now-=nl[L].l-nl[L-1].r-1; 59 } 60 while (L<ln && now>m) 61 { 62 L++; 63 now-=nl[L].l-nl[L-1].r-1; 64 } 65 if (L<=ln) ans=max(ans,(LL)(nl[ln].r-nl[L].l+1)+m-now); 66 printf("%lld ",ans); 67 } 68 return 0; 69 }
前面处理区间的部分可以优化,只要把区间按左端点排序,相同时右端点靠右的在前,然后时时记录枚举到的最右端点即可。---TJM。