zoukankan      html  css  js  c++  java
  • P1712 [NOI2016]区间

    题目描述

    在数轴上有 NN 个闭区间 [l_1,r_1],[l_2,r_2],...,[l_n,r_n][l1,r1],[l2,r2],...,[ln,rn] 。现在要从中选出 MM 个区间,使得这 MM 个区间共同包含至少一个位置。换句话说,就是使得存在一个 xx ,使得对于每一个被选中的区间 [l_i,r_i][li,ri] ,都有 l_i≤x≤r_ilixri 。

    对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。区间 [l_i,r_i][li,ri] 的长度定义为 r_i-l_irili ,即等于它的右端点的值减去左端点的值。

    求所有合法方案中最小的花费。如果不存在合法的方案,输出 -11 。

    输入输出格式

    输入格式:

     

    第一行包含两个正整数 N,MN,M 用空格隔开,意义如上文所述。保证 1≤M≤N1MN

    接下来 NN 行,每行表示一个区间,包含用空格隔开的两个整数 l_ili 和 r_iri 为该区间的左右端点。

    N<=500000,M<=200000,0≤li≤ri≤10^9N<=500000,M<=200000,0liri109

     

    输出格式:

     

    只有一行,包含一个正整数,即最小花费。

     

    输入输出样例

    输入样例#1: 
    6 3
    3 5
    1 2
    3 4
    2 2
    1 5
    1 4
    输出样例#1: 
    2

    说明

    Solution:

      今天PKU学长HRZ讲课,说到了本题,然后思路比较巧妙。

      方法就是对区间离散后,按原长度从小到大排序,然后用一个队列维护两个指针$l,r$,$O(n)$的去加入区间$s[l,r]+=1$,用线段树维护区间最大值,若区间最大值$geq m$则从前往后把加入的区间删除,直到区间最大值刚好$< m$,那么用$l-1$所保存的长度和当前加入的区间长度差去更新答案,然后就没了。

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define ll long long 
    #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
    #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    using namespace std;
    const int N=800005;
    int n,m,maxn[N<<3],add[N<<3],ans=0x7fffffff;
    int l=1,r;
    int *lst[N<<1],cnt,tot;
    struct node{
        int l,r,len;
        bool operator<(const node &a)const{return len<a.len;}
    }a[N],Q[N];
    
    il bool cmp(const int *a,const int *b) {return *a<*b;}
    
    il int gi(){
        int a=0;char x=getchar();bool f=0;
        while((x<'0'||x>'9')&&x!='-')x=getchar();
        if(x=='-')x=getchar(),f=1;
        while(x>='0'&&x<='9')a=(a<<1)+(a<<3)+x-48,x=getchar();
        return f?-a:a;
    }
    
    il void pushup(int rt){maxn[rt]=max(maxn[rt<<1],maxn[rt<<1|1]);}
    
    il void pushdown(int rt,int len){
        if(add[rt]){
            add[rt<<1]+=add[rt],
            add[rt<<1|1]+=add[rt];
            maxn[rt<<1]+=add[rt],
            maxn[rt<<1|1]+=add[rt];
            add[rt]=0;
        }
    }
    
    il void update(int L,int R,int k,int l,int r,int rt){
        pushdown(rt,r-l+1);
        if(L<=l&&R>=r){maxn[rt]+=k;add[rt]=k;return;}
        int m=l+r>>1;
        if(L<=m) update(L,R,k,lson);
        if(R>m) update(L,R,k,rson);
        pushup(rt);
    }
    
    int main(){
        n=gi(),m=gi();
        For(i,1,n) a[i].l=gi(),a[i].r=gi(),a[i].len=a[i].r-a[i].l,lst[++cnt]=&a[i].l,lst[++cnt]=&a[i].r;
        sort(lst+1,lst+cnt+1,cmp);
        int k=-1;
        For(i,1,cnt) {
            if(*lst[i]!=k) k=*lst[i],*lst[i]=++tot;
            else *lst[i]=tot;
        }
        sort(a+1,a+n+1);
        For(i,1,n) {
            Q[++r].l=a[i].l,Q[r].r=a[i].r,Q[r].len=a[i].len;
            update(a[i].l,a[i].r,1,1,tot,1);
            if(maxn[1]>=m){
                while(l<=r&&maxn[1]>=m){
                    update(Q[l].l,Q[l].r,-1,1,tot,1);
                    l++;
                }
                if(maxn[1]<m) ans=min(a[i].len-Q[l-1].len,ans);
            }
        }
        cout<<(ans==0x7fffffff?-1:ans);
        return 0;
    }
  • 相关阅读:
    面向对象设计与实用的思考(主动对象与被动对象)
    改进弧长法 判断点是否在多边形内 c#代码
    PaintCode begin
    kiwivm putty lnmp
    初心已变,我也不是当时的我
    spfa
    tree dp
    开心就好之修行ing
    MIME 参考手册
    TypeScript学习和参考手册
  • 原文地址:https://www.cnblogs.com/five20/p/9351015.html
Copyright © 2011-2022 走看看