zoukankan      html  css  js  c++  java
  • bzoj 4653: [Noi2016]区间

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

    解题报告:
    难得一道做得出的NOI,首先发现那一个相交的点一定可以是区间的某个端点,所以可以离散左右端点,那么问题就简单了,然后仔细推敲,发现可以按区间长度排序,然后不就是尺取法了么?如果有一个点被覆盖的次数>=m我们就移动左指针,不然我们就一直往后走,对于覆盖次数>=m我们就维护线段树区间最大值,然后区间修改维护指针移动即可

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    #define ls (node<<1)
    #define rs (node<<1|1)
    using namespace std;
    const int N=500005;
    int b[N<<1],num=0,n,m,tr[N<<4],mark[N<<4];
    struct node{
    	int l,r,val;
    	bool operator <(const node &pr)const{return val<pr.val;}
    }a[N];
    void upd(int node){tr[node]=Max(tr[ls],tr[rs]);}
    void pushdown(int node){
    	if(!mark[node])return ;
    	int k=mark[node];tr[ls]+=k;tr[rs]+=k;
    	mark[ls]+=k;mark[rs]+=k;mark[node]=0;
    }
    void updata(int l,int r,int node,int sa,int se,int ad){
    	if(l>se || r<sa)return ;
    	if(sa<=l && r<=se){tr[node]+=ad;mark[node]+=ad;return ;}
    	int mid=(l+r)>>1;pushdown(node);
    	updata(l,mid,ls,sa,se,ad);updata(mid+1,r,rs,sa,se,ad);
    	upd(node);
    }
    void work()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%d%d",&a[i].l,&a[i].r),a[i].val=a[i].r-a[i].l;
    		b[++num]=a[i].l;b[++num]=a[i].r;
    	}
    	sort(a+1,a+n+1);sort(b+1,b+num+1);
    	int tot=unique(b+1,b+num+1)-b-1;
    	for(int i=1;i<=n;i++){
    		a[i].l=lower_bound(b+1,b+tot+1,a[i].l)-b;
    		a[i].r=lower_bound(b+1,b+tot+1,a[i].r)-b;
    	}
    	int l=1,ans=2e9;
    	for(int i=1;i<=n;i++){
    		updata(1,tot,1,a[i].l,a[i].r,1);
    		while(tr[1]>=m && l<i){
    			ans=Min(ans,a[i].val-a[l].val);
    			updata(1,tot,1,a[l].l,a[l].r,-1);
    			l++;
    		}
    		if(tr[1]>=m)ans=Min(ans,a[i].val-a[l].val);
    	}
    	if(ans!=2e9)printf("%d
    ",ans);
    	else puts("-1");
    }
    
    int main()
    {
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    解决UITableView中Cell重用机制导致内容出错的方法总结
    Hdu 1052 Tian Ji -- The Horse Racing
    Hdu 1009 FatMouse' Trade
    hdu 2037 今年暑假不AC
    hdu 1559 最大子矩阵
    hdu 1004 Let the Balloon Rise
    Hdu 1214 圆桌会议
    Hdu 1081 To The Max
    Hdu 2845 Beans
    Hdu 2955 Robberies 0/1背包
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7570777.html
Copyright © 2011-2022 走看看