zoukankan      html  css  js  c++  java
  • NOI 2016 区间

    题目描述

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

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

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

    输入输出格式

    输入格式:

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

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

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

    输出格式:

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

    输入输出样例

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

    说明

    题解:

      首先,对于这个题目,我们先讲每个区间按照区间长度从小到大排序,那么显然,对于每个合法方案,讲他们从小到大排序,记最小区间为i,最大区间为j,那么这个合法方案,一定对应着sort后数组从l~R的一个区间,也就是说每个合法方案都对应了一个连续的区间l~r,其中最小的区间为l,最大的区间为r。这个性质十分显然。

      有了这个性质,就可以打一个n^2logn的暴力,(虽然用差分数组可以写一个n^2的暴力……),即:枚举l~r,线段数求交check,答案就是min(len[r]-len[l])。当然我们可以用决策单调性来优化这个暴力,用两个指针i,j,强制i为最小的区间,然后用j向后推移,知道区间的交>m时才停止,注意,j指针只向后移动,这个有点难想,证明简单,想一下就知道了。

    代码:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    const int MAXN = 1000011;
    using namespace std;
    int n,m;
    struct qvjian{
        int l,r,len;
    }q[MAXN*2];
    struct tree{
        int l,r,maxx,tag;
    }a[MAXN*8];
    int b[MAXN*2],num,k,j=1,ans=1<<30;
    
    bool cmp(qvjian x,qvjian y){
        return x.len<y.len;
    }
    
    void pushdown(int xv){
        if(!a[xv].tag) return;
        a[xv*2].maxx+=a[xv].tag,a[xv*2+1].maxx+=a[xv].tag;
        a[xv*2].tag+=a[xv].tag,a[xv*2+1].tag+=a[xv].tag;
        a[xv].tag=0;
    }
    
    void pushup(int xv){
        a[xv].maxx=max(a[xv*2].maxx,a[xv*2+1].maxx);
    }
    
    void build(int xv,int l,int r){
        if(l==r){
            a[xv].l=l,a[xv].r=r,a[xv].tag=0,a[xv].maxx=0;
            return;
        }
        a[xv].l=l,a[xv].r=r,a[xv].tag=0;
        int mid=(l+r)/2;
        build(xv*2,l,mid),build(xv*2+1,mid+1,r);
        pushup(xv);
    }
    
    void change(int xv,int l,int r,int x){
        int L=a[xv].l,R=a[xv].r,mid=(L+R)/2;
        if(l==L&&r==R){
            a[xv].tag+=x;
            a[xv].maxx+=x;
            return;
        }
        pushdown(xv);
        if(r<=mid) change(xv*2,l,r,x);
        else if(l>mid) change(xv*2+1,l,r,x);
        else change(xv*2,l,mid,x),change(xv*2+1,mid+1,r,x);
        pushup(xv);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d%d",&q[i].l,&q[i].r),b[++num]=q[i].l,b[++num]=q[i].r;q[i].len=q[i].r-q[i].l;
        }
        sort(q+1,q+n+1,cmp);sort(b+1,b+num+1);
        k=unique(b,b+num+1)-b-1;
        for(int i=1;i<=n;i++){
            q[i].l=lower_bound(b+1,b+k+1,q[i].l)-b,q[i].r=lower_bound(b+1,b+k+1,q[i].r)-b;
        }
        build(1,1,k);
        for(int i=1;i<=n;i++){
            while(a[1].maxx<m){
                if(j>=n) break;j++;
                change(1,q[j].l,q[j].r,1);
            }
            if(j>=n) break;
            ans=min(ans,q[j].len-q[i].len);
            change(1,q[i].l,q[i].r,-1);
        }
        if(ans==1<<30) printf("-1
    ");
        else printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    POJ 2251 Dungeon Master
    HDU 3085 Nightmare Ⅱ
    CodeForces 1060 B Maximum Sum of Digits
    HDU 1166 敌兵布阵(树状数组)
    HDOJ 2050 折线分割平面
    HDU 5879 Cure
    HDU 1878 欧拉回路
    HDU 6225 Little Boxes
    ZOJ 2971 Give Me the Number
    HDU 2680 Choose the best route
  • 原文地址:https://www.cnblogs.com/renjianshige/p/7576497.html
Copyright © 2011-2022 走看看