[BZOJ4653 区间]

Description

在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn]。现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置。换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri。
对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。区间 [li,ri] 的长度定义为 ri−li,即等于它的右端点的值减去左端点的值。
求所有合法方案中最小的花费。如果不存在合法的方案,输出 −1。

Input

第一行包含两个正整数 n,m用空格隔开,意义如上文所述。保证 1≤m≤n
接下来 n行,每行表示一个区间,包含用空格隔开的两个整数 li 和 ri 为该区间的左右端点。
N<=500000,M<=200000,0≤li≤ri≤10^9

Output

只有一行,包含一个正整数,即最小花费。

Sample Input

6 3
3 5
1 2
3 4
2 2
1 5
1 4

Sample Output

2
 
双指针扫一下即可,难得的noi水题
代码:
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define M 1000010
 6 #define int long long
 7 #define ls node<<1
 8 #define rs node<<1|1
 9 using namespace std;
10 int read()
11 {
12     char ch=getchar();int x=0;
13     while(ch>'9'||ch<'0') ch=getchar();
14     while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
15     return x;
16 }
17 
18 int l,r,n,m,tmp,ans=1e18;
19 int b[M<<2],cnt[M<<2],tag[M<<2];
20 struct point{int l,r;}a[M];
21 bool cmp(point a1,point a2) {return a1.r-a1.l<a2.r-a2.l;}
22 
23 void getans(int l,int r) 
24 {
25     ans=min(ans,b[a[r].r]-b[a[r].l]+b[a[l].l]-b[a[l].r]);
26 }
27 
28 int get(int x)
29 {
30     int l=1,r=tmp;
31     while(l<=r)
32     {
33         int mid=(l+r)/2;
34         if(b[mid]==x) return mid;
35         if(b[mid]<x) l=mid+1;
36         else r=mid-1;
37     }
38 }
39 
40 void push(int node)
41 {
42     if(tag[node]!=0)
43     {
44         tag[ls]+=tag[node];
45         tag[rs]+=tag[node];
46         cnt[ls]+=tag[node];
47         cnt[rs]+=tag[node];
48         tag[node]=0;
49     }
50 }
51 
52 void change(int node,int l,int r,int l1,int r1,int v)
53 {
54     if(l1<=l&&r1>=r)
55     {
56         cnt[node]+=v;
57         tag[node]+=v;
58         return;
59     }
60     if(l1>r||r1<l) return;
61     int mid=(l+r)/2; push(node);
62     change(ls,l,mid,l1,r1,v);
63     change(rs,mid+1,r,l1,r1,v);
64     cnt[node]=max(cnt[ls],cnt[rs]);
65 }
66 
67 main()
68 {
69     n=read(); m=read();
70     for(int i=1;i<=n;i++) 
71     {
72         a[i].l=read(),a[i].r=read();
73         b[++tmp]=a[i].l,b[++tmp]=a[i].r;
74     }
75     sort(a+1,a+1+n,cmp);
76     sort(b+1,b+1+tmp);
77     tmp=unique(b+1,b+1+tmp)-b-1;
78     for(int i=1;i<=n;i++) 
79     {
80         a[i].l=get(a[i].l);
81         a[i].r=get(a[i].r);
82     }
83     while(1)
84     {
85         while(cnt[1]>=m)
86         {
87             getans(l,r);
88             change(1,1,tmp,a[l].l,a[l].r,-1);
89             l++;
90         }
91         if(r==n) break;
92         r++;
93         change(1,1,tmp,a[r].l,a[r].r,1);
94     }
95     if(ans==1e18) puts("-1");
96     else printf("%lld",ans);
97     return 0;
98 }

 

转载于:https://www.cnblogs.com/Slrslr/p/9740860.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值