http://acm.hdu.edu.cn/showproblem.php?pid=6119
【思路】
- 首先通过处理交叉的可以处理成不交叉的
- 然后二分查找答案
- 如何判断一个长度是否可行?
- 双指针O(n)扫一次就可以,要处理区间和问题,所以先求前缀和
- 时间复杂度O(nlogn)
【AC】
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #include<cmath> 7 8 using namespace std; 9 typedef long long ll; 10 const int maxn=1e5+3; 11 int n,m; 12 int cnt1,cnt2; 13 struct node 14 { 15 int l; 16 int r; 17 }a[maxn]; 18 int b[maxn]; 19 int c[maxn]; 20 int pre1[maxn]; 21 int pre2[maxn]; 22 23 bool cmp(node x,node y) 24 { 25 if(x.l!=y.l) return x.l<y.l; 26 return x.r<y.r; 27 } 28 void Pre() 29 { 30 memset(pre1,0,sizeof(pre1)); 31 pre1[0]=b[0]; 32 for(int i=1;i<cnt1;i++) 33 { 34 pre1[i]=pre1[i-1]+b[i]; 35 } 36 memset(pre2,0,sizeof(pre2)); 37 pre2[0]=c[0]; 38 for(int i=1;i<cnt2;i++) 39 { 40 pre2[i]=pre2[i-1]+c[i]; 41 } 42 43 } 44 bool check(int p,int q,int mid) 45 { 46 if(p==0) return pre1[q]>=mid; 47 return pre1[q]-pre1[p-1]>=mid; 48 } 49 bool judge(int mid) 50 { 51 int pos=upper_bound(pre2,pre2+cnt2,m)-pre2-1; 52 int totm=pre2[pos]; 53 int p=0,q=pos+1; 54 while(p<=q&&q<cnt1) 55 { 56 if(check(p,q,mid)) 57 { 58 return true; 59 } 60 else 61 { 62 totm-=c[p]; 63 p++; 64 while(pos+1<cnt2&&totm+c[pos+1]<=m) 65 { 66 totm+=c[pos+1]; 67 pos++; 68 } 69 q=pos+1; 70 } 71 } 72 return false; 73 } 74 int main() 75 { 76 while(scanf("%d%d",&n,&m)!=EOF) 77 { 78 for(int i=0;i<n;i++) 79 { 80 scanf("%d%d",&a[i].l,&a[i].r); 81 } 82 sort(a,a+n,cmp); 83 cnt1=0; 84 cnt2=0; 85 int p=a[0].l,q=a[0].r; 86 int low=0,high=0; 87 for(int i=1;i<n;i++) 88 { 89 if(a[i].l<=q) 90 { 91 q=max(q,a[i].r); 92 } 93 else 94 { 95 b[cnt1++]=q-p+1; 96 high+=q-p+1; 97 c[cnt2++]=a[i].l-q-1; 98 p=a[i].l; 99 q=a[i].r; 100 } 101 } 102 b[cnt1++]=q-p+1; 103 high+=q-p+1; 104 Pre(); 105 while(low<=high) 106 { 107 int mid=(low+high)>>1; 108 if(judge(mid)) 109 { 110 low=mid+1; 111 } 112 else 113 { 114 high=mid-1; 115 } 116 } 117 cout<<low+m-1<<endl; 118 } 119 return 0; 120 }