1. 程式人生 > >[Noi2016]區間

[Noi2016]區間

space main urn () cstring 大於 pushd cdn cnblogs

題目描述

在數軸上有 n個閉區間 [l1,r1],[l2,r2],...,[ln,rn]。現在要從中選出 m 個區間,使得這 m個區間共同包含至少一個位置。換句話說,就是使得存在一個 x,使得對於每一個被選中的區間 [li,ri],都有 li≤x≤ri。

對於一個合法的選取方案,它的花費為被選中的最長區間長度減去被選中的最短區間長度。區間 [li,ri] 的長度定義為 ri?li,即等於它的右端點的值減去左端點的值。

求所有合法方案中最小的花費。如果不存在合法的方案,輸出 ?1。

輸入輸出格式

輸入格式:

第一行包含兩個正整數 n,m用空格隔開,意義如上文所述。保證 1≤m≤n

接下來 n行,每行表示一個區間,包含用空格隔開的兩個整數 li 和 ri 為該區間的左右端點。

N<=500000,M<=200000,0≤li≤ri≤10^9

輸出格式:

只有一行,包含一個正整數,即最小花費。

輸入輸出樣例

輸入樣例#1:
6 3
3 5
1 2
3 4
2 2
1 5
1 4
輸出樣例#1:
2

說明

技術分享

技術分享

題解:

離散化+線段樹維護+決策單調性

先將數據離散,但區間長不變。

按區間長從小到大排序,可知單調性:當最大值大於m時,再增加區間不會使答案減小,即當前最優解(意思是不必在往後走,而不是全局最優)。

具體實現與單調隊列一樣,不過區間的和用線段樹維護,當小於m時入隊

將當前答案與ans比較記下,隊首出隊,繼續執行。

註意隊尾要小於等於n,與ans比較時,區間和必須大於m

 1 #include<iostream>  
 2 #include<cstring>  
 3 #include<cstdio> 
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;  
 7 struct Messi
 8 {
 9     int x,y,l;
10 }a[10000111];
11 int k,p[10000111],lazy[10000110],c[10000111],n,m,ans;
12 bool vis[10000111];
13 int find(int x)
14 {int l,r; 15 l=1;r=k; 16 while (l<r) 17 { 18 int mid=(l+r)/2; 19 if (p[mid]>=x) r=mid; 20 else l=mid+1; 21 } 22 return l; 23 } 24 bool cmp(Messi a,Messi b) 25 { 26 return (a.l<b.l); 27 } 28 void pushdown(int rt) 29 { 30 if (lazy[rt]!=0) 31 { 32 lazy[rt*2]+=lazy[rt]; 33 lazy[rt*2+1]+=lazy[rt]; 34 c[rt*2]+=lazy[rt]; 35 c[rt*2+1]+=lazy[rt]; 36 lazy[rt]=0; 37 } 38 } 39 void update(int rt,int l,int r,int L,int R,int k) 40 { 41 if (l!=r) pushdown(rt); 42 if (l>=L&&r<=R) 43 { 44 c[rt]+=k; 45 lazy[rt]+=k; 46 return; 47 } 48 49 int mid=(l+r)/2; 50 if (L<=mid) update(rt*2,l,mid,L,R,k); 51 if (R>mid) update(rt*2+1,mid+1,r,L,R,k); 52 c[rt]=max(c[rt*2],c[rt*2+1]); 53 } 54 int main() 55 {int i,j; 56 cin>>n>>m; 57 for (i=1;i<=n;i++) 58 { 59 scanf("%d%d",&a[i].x,&a[i].y); 60 { 61 k++; 62 p[k]=a[i].x; 63 } 64 { 65 k++; 66 p[k]=a[i].y; 67 } 68 a[i].l=a[i].y-a[i].x; 69 } 70 sort(p+1,p+k+1); 71 for (i=1;i<=n;i++) 72 { 73 a[i].x=find(a[i].x); 74 a[i].y=find(a[i].y); 75 } 76 sort(a+1,a+n+1,cmp); 77 j=0; 78 ans=2e9; 79 for (i=1;i<=n;i++) 80 { 81 if (j==n) break; 82 while (c[1]<m&&j<n) 83 { 84 j++; 85 update(1,1,k,a[j].x,a[j].y,1); 86 } 87 if (c[1]>=m) ans=min(a[j].l-a[i].l,ans); 88 update(1,1,k,a[i].x,a[i].y,-1); 89 } 90 if (ans==2e9) 91 cout<<-1; 92 else 93 cout<<ans; 94 }

[Noi2016]區間