[BZOJ4653][NOI2016]区间 贪心+线段树
4653: [Noi2016]区间
Time Limit: 60 Sec Memory Limit: 256 MBDescription
在数轴上有 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
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\n",(ans==inf)?-1:ans); 58 }
Progress is not created by contented people.