• NOI 2016 区间


    洛谷 P1712 [NOI2016]区间

    题目传送门

    题目描述

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

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

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

    输入格式

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

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

    N<=500000,M<=200000,0≤li≤ri≤10^9N<=500000,M<=200000,0≤l**ir**i≤109

    输出格式

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

    输入输出样例

    输入 #1复制

    输出 #1复制

    说明/提示

    img

    img

    题解:

    (第二道紫题)

    (开心)

    这是一道线段树的题,加了一点点的尺取法思想(为此我特意学了尺取法)

    所以我们得出这样的思路,先按照区间长度大小排序,进行离散化,按照我们排过序后的顺序依次加入区间,然后看一下是否有一个点的区间被覆盖的次数大于等于m,如果有的话,我们还需要统计最小长度,就尝试着把前面的内容依次删除,知道<m(临界点)。

    其实这就是一个尺取法的过程。

    通过上述的思路,我们发现这个思路代码实现上的难点一个是离散化,一个是尺取,还有一个就是如何统计得出有一个点的被覆盖次数比m大。

    显然暴力枚举是不行的,所以我们考虑线段树维护这个覆盖次数。

    所以就可以了。

    代码大致如下:

    #include<cstdio>
    #include<algorithm>
    #define lson pos<<1
    #define rson pos<<1|1
    using namespace std;
    const int maxn=500001;
    const int INF=1e9;
    struct Point
    {
        int val,id;
    }p[maxn<<2];
    struct Data
    {
        int len,id;
    }a[maxn<<2];
    int L[maxn<<1],R[maxn<<1],n,m,maxr,cnt,num;
    int tree[maxn<<3],add[maxn<<3];
    bool cmp1(Point a,Point b)
    {
        return a.val<b.val;
    }
    bool cmp2(Data a,Data b)
    {
        return a.len<b.len;
    }
    void pushdown(int pos,int l,int r)
    {
        if(!add[pos])
            return;
        tree[lson]+=add[pos];
        tree[rson]+=add[pos];
        add[lson]+=add[pos];
        add[rson]+=add[pos];
        add[pos]=0;
        return;
    }
    void fix(int pos,int l,int r,int x,int y,int val)
    {
        if(x>r||y<l)
            return;
        if(x<=l&&y>=r)
        {
            tree[pos]+=val;
            add[pos]+=val;
            return;
        }
        int mid=(l+r)/2;
        pushdown(pos,l,r);
        fix(lson,l,mid,x,y,val);
        fix(rson,mid+1,r,x,y,val);
        tree[pos]=max(tree[lson],tree[rson]);
        return;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            a[i].len=v-u;
            a[i].id=i;
            p[++cnt].val=u;
            p[cnt].id=i;
            p[++cnt].val=v;
            p[cnt].id=i;
        }
        p[0].val=-1;
        sort(p+1,p+cnt+1,cmp1);
        for(int i=1;i<=cnt;i++)
        {
            if(p[i].val!=p[i-1].val)
                num++;
            int order=p[i].id;
            if(!L[order])
                L[order]=num;
            else 
                R[order]=num;
        }
        maxr=num;
        sort(a+1,a+n+1,cmp2);
        int ans=INF,le=0,ri=0;
        while(1)
        {
            while(tree[1]<m && ri<=n)
            {
                ri++;
                int u=a[ri].id,v=L[u],w=R[u];
                fix(1,1,maxr,v,w,1);
            }
            if(tree[1]<m)
                break;
            while(tree[1]>=m && le<=n)
            {
                le++;
                int u=a[le].id,v=L[u],w=R[u];
                fix(1,1,maxr,v,w,-1);
            }
            ans=min(ans,a[ri].len-a[le].len);
        }
        if(ans==INF)
            printf("-1");
        else
            printf("%d",ans);
        return 0;
    }
    
  • 相关阅读:
    数据库之小问题
    网络基础
    react-fiber 解析
    【like-react】手写一个类似 react 的框架
    istat menus 序列号
    Git学习
    JavaScript设计模式与开发实践【第一部分】
    javascript 原生bind方法实现
    requirejs 学习
    mac 安装maven+eclipse
  • 原文地址:https://www.cnblogs.com/fusiwei/p/11314125.html
Copyright © 2020-2023  润新知