zoukankan      html  css  js  c++  java
  • BZOJ4653 & 洛谷1712 & UOJ222:[NOI2016]区间——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4653

    https://www.luogu.org/problemnew/show/P1712

    http://uoj.ac/problem/222

    在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn]。现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置。换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri。

    对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。区间 [li,ri] 的长度定义为 ri−li,即等于它的右端点的值减去左端点的值。
    求所有合法方案中最小的花费。如果不存在合法的方案,输出 −1。

    (天哪我终于会做套路题了……虽然对于判断是否合法的时候没想到线段树……)

    看复杂度是O(nlogn)猜想可能又是枚举左端点找右端点的套路。

    然而相比于一个点被覆盖m次,更难处理的是这个答案的运算。

    于是我们将区间按照权值排序,接着就是两个指针不断扩大,当合法的时候更新一下答案就行了。

    那么如何维护一个点被最多被覆盖了多少次呢?线段树呗。

    注意空间不要开小了-=-

    #include<cmath>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int INF=2e9;
    const int N=5e5+5;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct range{
        int l,r,w;
    }g[N];
    int n,m,lim,b[2*N],tr[8*N],lz[8*N];
    inline bool cmp(range a,range b){
        return a.w<b.w;
    }
    inline void LSH(){
        sort(b+1,b+lim+1);
        lim=unique(b+1,b+lim+1)-b-1;
        for(int i=1;i<=n;i++){
        g[i].l=lower_bound(b+1,b+lim+1,g[i].l)-b;
        g[i].r=lower_bound(b+1,b+lim+1,g[i].r)-b;
        }
    }
    inline void push(int a){
        if(!lz[a])return;
        lz[a<<1]+=lz[a];lz[a<<1|1]+=lz[a];
        tr[a<<1]+=lz[a];tr[a<<1|1]+=lz[a];
        lz[a]=0;
    }
    void insert(int a,int l,int r,int l1,int r1,int w){
        if(r<l1||r1<l)return;
        if(l1<=l&&r<=r1){
        tr[a]+=w;lz[a]+=w;
        return;
        }
        push(a);
        int mid=(l+r)>>1;
        insert(a<<1,l,mid,l1,r1,w);
        insert(a<<1|1,mid+1,r,l1,r1,w);
        tr[a]=max(tr[a<<1],tr[a<<1|1]);
    }
    int main(){
        n=read(),m=read();
        for(int i=1;i<=n;i++){
        g[i].l=b[++lim]=read();
        g[i].r=b[++lim]=read();
        g[i].w=g[i].r-g[i].l;
        }
        LSH();
        sort(g+1,g+n+1,cmp);
        int l=1,ans=INF;
        for(int l=1,r=0;l<=n;l++){
        while(r<n&&tr[1]<m){
            r++;
            insert(1,1,lim,g[r].l,g[r].r,1);
        }
        if(tr[1]>=m)ans=min(ans,g[r].w-g[l].w);
        insert(1,1,lim,g[l].l,g[l].r,-1);
        }
        printf("%d
    ",ans==INF?-1:ans);
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

     +本文作者:luyouqi233。               +

     +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    txtbox取Calendar值
    【Spread Sheet 应用(一)】去掉原有功能键及添加功能键
    【SQLSERVER】存储过程基础
    【SQLSERVER】在存储过程中调用存储过程
    ASP.NET跨页面传值技巧(VB.NET篇)
    【EXCEL】IF...ELSE语句
    VB单元测试
    【VB.NET】窗体之间传值
    【Spread Sheet 应用(二)】常用属性设置
    【SQLSERCER】创建、改变、删除索引
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9132055.html
Copyright © 2011-2022 走看看