码迷,mamicode.com
首页 > 其他好文 > 详细

[UOJ #222][NOI2016]区间(线段树)

时间:2017-05-04 13:22:35      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:blog   ring   bool   style   date   cstring   names   void   top   

Description

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

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

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

Solution

对区间的长度排序,离散化,然后线段树维护每个点被覆盖过的次数,根据决策的单调性就可做了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define MAXN 500005
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
int a[MAXN*2],cnt=0;
int read()
{
    int x=0,f=1;char c=getchar();
    while(c<0||c>9){
        if(c==-)f=-1;c=getchar();
    }
    while(c>=0&&c<=9){
        x=x*10+c-0;c=getchar();
    }
    return x*f;
}
struct Node1
{
    int L,R,len;
}d[MAXN];
bool cmp(Node1 x,Node1 y)
{
    return x.len<y.len; 
}
struct Node2
{
    int l,r,tag,maxn;
}t[MAXN*8];
void pushdown(int idx)
{
    if(t[idx].tag&&t[idx].l!=t[idx].r)
    {
        int tag=t[idx].tag;
        t[idx].tag=0;
        t[idx<<1].tag+=tag;
        t[idx<<1|1].tag+=tag;
        t[idx<<1].maxn+=tag;
        t[idx<<1|1].maxn+=tag;
    }
}
void update(int idx)
{
    t[idx].maxn=max(t[idx<<1].maxn,t[idx<<1|1].maxn);
}
void build(int idx,int l,int r)
{
    t[idx].l=l,t[idx].r=r,t[idx].maxn=t[idx].tag=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(idx<<1,l,mid);
    build(idx<<1|1,mid+1,r);
}
void add(int idx,int x,int y,int z)
{
    
    if(x<=t[idx].l&&y>=t[idx].r)
    {
        t[idx].maxn+=z;
        t[idx].tag+=z;
        return;
    }
    pushdown(idx);
    int mid=(t[idx].l+t[idx].r)>>1;
    if(y<=mid)add(idx<<1,x,y,z);
    else if(x>mid)add(idx<<1|1,x,y,z);
    else add(idx<<1,x,y,z),add(idx<<1|1,x,y,z);
    update(idx);
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    {
        d[i].L=read(),d[i].R=read();
        a[++cnt]=d[i].L,a[++cnt]=d[i].R;
        d[i].len=d[i].R-d[i].L; 
    }
    sort(a+1,a+1+cnt);
    cnt=unique(a+1,a+1+cnt)-a-1;
    sort(d+1,d+1+n,cmp);
    for(int i=1;i<=n;i++)
    {
        d[i].L=lower_bound(a+1,a+1+cnt,d[i].L)-a;
        d[i].R=lower_bound(a+1,a+1+cnt,d[i].R)-a;
    }
    int ans=INF,top=0;
    build(1,1,cnt);
    for(int i=1;i<=n;i++)
    {
        while(top<n&&t[1].maxn<m)
        {
            ++top;
            add(1,d[top].L,d[top].R,1);
        }
        if(t[1].maxn>=m)ans=min(ans,d[top].len-d[i].len);
        add(1,d[i].L,d[i].R,-1);
    }
    if(ans==INF)printf("-1\n");
    else printf("%d\n",ans);
    return 0;
} 

 

[UOJ #222][NOI2016]区间(线段树)

标签:blog   ring   bool   style   date   cstring   names   void   top   

原文地址:http://www.cnblogs.com/Zars19/p/6806481.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!