zoukankan      html  css  js  c++  java
  • Evanyou Blog 彩带

      题目传送门

    区间

    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

      分析:

      一开始直接贪心+离散线段树,然后WA得天花乱坠,T飞到了九霄云外。。。还是太naive了。。。

      首先,我们能想到这样一个思路:首先对区间按照长度进行排序,这个贪心应该是显然的;然后依次将加入区间,这里加入区间是指将该区间$[l,r]$内的所有权值+1,这样就可以得到,只要有一个点的权值大于或等于$m$,那么就可以更新答案。

      维护权值不难想到用权值线段树,但是数据范围太大需要离散化(一开始还在离散卡了好久。。。太菜了。。。)。

      更新答案的时候依次将前面添加的区间减掉,直到所有点的权值都小于$m$,然后就可以找到该情况下更新的答案。这是用到尺取法的思想。

      Code:

     

    //It is made by HolseLee on 23rd July 2018
    //BZOJ 4653
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=5e5+7;
    int n,m,ans,l[N],r[N],inf=-1;
    
    struct Seg{
        int id,len;
        bool operator < (const Seg x) const {
            return len<x.len;
        }
    }a[N],p[N<<1];
    
    inline int Max(int x,int y)
    {
        return x>y?x:y;
    }
    
    struct segment{
        int s[N<<4],sign[N<<4];
        
        void ready()
        {
            memset(s,0,sizeof(s));
            memset(sign,0,sizeof(sign));
        } 
        
        void pushup(int rt)
        {
            s[rt]=Max(s[rt<<1],s[rt<<1|1]);
        }
        
        void pushdown(int rt)
        {
            if(!sign[rt])return;
            s[rt<<1]+=sign[rt];
            s[rt<<1|1]+=sign[rt];
            sign[rt<<1]+=sign[rt];
            sign[rt<<1|1]+=sign[rt];
            sign[rt]=0;
        }
        
        void update(int l,int r,int rt,int L,int R,int C)
        {
            if(l>R||r<L)return;
            if(L<=l&&r<=R){
                s[rt]+=C;sign[rt]+=C;return;}
            int mid=(l+r)>>1;
            pushdown(rt);
            if(L<=mid)update(l,mid,rt<<1,L,R,C);
            if(R>mid)update(mid+1,r,rt<<1|1,L,R,C);
            pushup(rt);
        }
    }T;
    
    inline int read()
    {
        char ch=getchar();int num=0;bool flag=false;
        while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
        while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
        return flag?-num:num;
    }
    
    int main()
    {
        n=read();m=read();int x,y,z,cnt=0,tot=0;
        for(int i=1;i<=n;i++){
            x=read();y=read();
            a[i].len=y-x;a[i].id=i;
            p[++cnt].len=x;p[cnt].id=i;
            p[++cnt].len=y;p[cnt].id=i;
        }
        sort(p+1,p+cnt+1);
        for(int i=1;i<=cnt;i++){
            x=p[i].id;tot++;
            if(!l[x]) l[x]=tot;
            else r[x]=tot;
        }
        sort(a+1,a+n+1);
        inf=tot;T.ready();
        int le=0,ri=0;
        ans=998244353;
        while(555){
            while(T.s[1]<m&&ri<=n){
                z=a[++ri].id;x=l[z];y=r[z];
                T.update(1,inf,1,x,y,1);
            }
            if(T.s[1]<m)break;
            while(T.s[1]>=m&&le<=n){
                z=a[++le].id;x=l[z];y=r[z];
                T.update(1,inf,1,x,y,-1);
            }
            ans=min(ans,a[ri].len-a[le].len);
        }
        if(ans==998244353)ans=-1;
        printf("%d",ans);
        return 0;
    }

     

     

  • 相关阅读:
    Sqlserver 还原那些事
    Sqlserver CheckPoint 在三种恢复模式中的不同表现
    转 SQL Server中关于的checkpoint使用说明
    类继承中的 隐藏和重写的 区别
    转 关于C#中派生类调用基类构造函数的理解
    Sqlserver 笔记 持续更新
    Asp.net 执行回调操作后 无法更新ViewState的问题
    c# double decimal
    table用模板生成的问题
    MVC接收列表参数
  • 原文地址:https://www.cnblogs.com/cytus/p/9357149.html
Copyright © 2011-2022 走看看