[BZOJ4653][NOI2016]区间 贪心+线段树

4653: [Noi2016]区间

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。

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
 
题解:
拿到这个题,应该都有一种贪心的冲动
但是贪心贪的好不好就决定了能不能过……
我们先拿一棵线段树来维护区间加和全局最大值操作,
添加线段转化为区间+1,当全局最大值>=m时,我们就找到了一组合法解:虽然我们不知道到底是谁,但全局最大值已经>=m,线段集合中对应的m条线段就是合法解
现在问题就变成了找谁是合法解。
把线段按照长度排序,那么我们按照顺序添加这些线段,如果找到一组最优解,就先把找到的线段集合中最大值看成选择的最后那条线段,最小值看成第一条线段,然后把最小值向右逼近,看能不能更优,这样O(n)扫一遍,同时一直记录合法解的最小值,就能找到最后的答案了!
代码见下:
 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <map>
 5 using namespace std;
 6 const int N=500100,inf=0x7fffffff;
 7 map<int,int> mp;
 8 int stack[N<<1],top,cnt,n,m;
 9 struct line{int l,r,len;}seg[N];
10 inline bool mt(const line &a,const line &b){return a.len<b.len;}
11 struct node
12 {
13     node *ch[2];int maxn,mark;
14     node(){ch[1]=ch[0]=NULL;mark=maxn=0;}
15     inline void update(){maxn=max(ch[0]->maxn,ch[1]->maxn)+mark;}
16 }*null=new node(),*root=null;
17 inline node* newnode()
18 {
19     node *o=new node();
20     o->maxn=o->mark=0;
21     o->ch[0]=o->ch[1]=null;
22     return o;
23 }
24 inline void add(node *&rt,int l,int r,int L,int R,int val)
25 {
26     if(rt==null)rt=newnode();
27     if(L<=l&&r<=R){rt->maxn+=val,rt->mark+=val;return;}
28     int mi=(l+r)>>1;
29     if(L<=mi)add(rt->ch[0],l,mi,L,R,val);
30     if(mi<R)add(rt->ch[1],mi+1,r,L,R,val);
31     rt->update();
32 }
33 int main()
34 {
35     scanf("%d%d",&n,&m);int ans=inf;
36     for(int i=1;i<=n;i++)
37     {
38         scanf("%d%d",&seg[i].l,&seg[i].r);
39         seg[i].len=seg[i].r-seg[i].l;
40         stack[++top]=seg[i].l,stack[++top]=seg[i].r;
41     }
42     sort(stack+1,stack+top+1);stack[0]=-inf;
43     for(int i=1;i<=top;i++)
44         if(stack[i]!=stack[i-1])mp[stack[i]]=++cnt;
45     for(int i=1;i<=n;i++)seg[i].l=mp[seg[i].l],seg[i].r=mp[seg[i].r];
46     sort(seg+1,seg+n+1,mt);root=newnode();
47     for(int i=1,j=1;i<=n;i++)
48     {
49         add(root,1,cnt,seg[i].l,seg[i].r,1);
50         while(root->maxn>=m)
51         {
52             ans=min(ans,seg[i].len-seg[j].len);
53             add(root,1,cnt,seg[j].l,seg[j].r,-1);
54             j++;
55         }
56     }
57     printf("%d
",(ans==inf)?-1:ans);
58 }
原文地址:https://www.cnblogs.com/LadyLex/p/7242808.html