区间
Time Limit: 60 Sec Memory Limit: 256 MB
Description
在数轴上有 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 为该区间的左右端点。
Output
只有一行,包含一个正整数,即最小花费。
6 3
3 5
1 2
3 4
2 2
1 5
1 4
Sample Output
2
HINT
N<=500000,M<=200000,0≤li≤ri≤10^9
Main idea
给定若干个区间,取出m个若这m个包含同一个位置则可以统计值,值为这m个中的最大区间长度减去最小区间长度,输出最小值。
Solution
发现答案为最大区间长度减去最小区间长度,显然可以先按照长度排序,然后枚举左端点(即最小区间长度),中间小于最大区间长度的区间的加入 只会使得更可能满足条件 而不会影响答案,所以我们用r表示当前加入到了右端点r这个位置,r显然递增,则可以用r一直往后推到满足条件了更新答案,用线段树维护区间+1。因为l[i]与r[i]长度较大,但是发现非常长的长度是不会影响是否可以统计的(因为满足统计的条件只要符合个数>=m即可),所以我们可以对l和r离散化。
Code
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
| #include<bits/stdc++.h> using namespace std;
const int ONE=1000001; const int INF=2147483640;
int n,m; int Ans,res; int num,cnt;
struct lisan { int pos; int value; }Q[ONE*2];
struct point { int l,r; int value; }a[ONE];
struct power { int value; int add; }Node[ONE*4];
int cmp(const point &a,const point &b) { return a.value<b.value; }
int rule(const lisan &a,const lisan &b) { return a.value<b.value; }
void pushdown(int i) { if(Node[i].add) { Node[i*2].add+=Node[i].add; Node[i*2+1].add+=Node[i].add; Node[i*2].value+=Node[i].add; Node[i*2+1].value+=Node[i].add; Node[i].add=0; } }
void Update(int i,int l,int r,int L,int R,int x) { if(L<=l && r<=R) { Node[i].add+=x; Node[i].value+=x; return; } pushdown(i);
int mid=(l+r)/2; if(L<=mid) Update(i*2,l,mid,L,R,x); if(mid+1<=R) Update(i*2+1,mid+1,r,L,R,x); Node[i].value=max(Node[i*2].value,Node[i*2+1].value); }
int get() { int res,Q=1; char c; while( (c=getchar())<48 || c>57) if(c=='-')Q=-1; if(Q) res=c-48; while((c=getchar())>=48 && c<=57) res=res*10+c-48; return res*Q; }
void Getlisan() { for(int i=1;i<=n;i++) { Q[++num].value=a[i].l; Q[num].pos=num; Q[++num].value=a[i].r; Q[num].pos=num; }
sort(Q+1,Q+num+1,rule); Q[0].value=-1; for(int i=1;i<=num;i++) { if(Q[i].value!=Q[i-1].value) cnt++; int x=(Q[i].pos+1)/2; if(Q[i].pos % 2) a[x].l=cnt; else a[x].r=cnt; }
sort(a+1,a+n+1,cmp); }
int main() { n=get(); m=get(); for(int i=1;i<=n;i++) { a[i].l=get(); a[i].r=get(); a[i].l++; a[i].r++; a[i].value=a[i].r-a[i].l; } Getlisan();
int r=0; Ans=INF; for(int i=1;i<=n;i++) { for(;;) { if(Node[1].value>=m || (r+1)>n) break; r++; Update(1,1,cnt,a[r].l,a[r].r,1); } if(Node[1].value>=m) Ans=min(Ans,a[r].value-a[i].value);
Update(1,1,cnt,a[i].l,a[i].r,-1); }
if(Ans==INF) printf("-1"); else printf("%d",Ans); }
|