bzoj4653 [Noi2016]区间 线段树

90 篇文章 0 订阅

Description


在数轴上有 n个闭区间 [l1,r1],[l2,r2],…,[ln,rn]。现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置。换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri。
对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。区间 [li,ri] 的长度定义为 ri−li,即等于它的右端点的值减去左端点的值。
求所有合法方案中最小的花费。如果不存在合法的方案,输出 −1。

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

Solution


首先考虑给区间按照长度排序,反正不影响答案是不是(滑稽
那么一段中的首尾决定了这一段的价值,我们只需要每次加入一个新的区间,查询是否有位置被覆盖了m次,每次把最右的区间去掉
要求资瓷动态区间修改、动态查询最值,上线段树即可
一开始没搞-1的情况于是gg了
就酱

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

const int INF=0x7fffffff;
const int N=2000005;

struct line{int l,r,v;} l[N];

int max[N*4],tag[N*4],b[N];

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void push_down(int now) {
    if (!tag[now]) return ;
    int tmp=tag[now]; tag[now]=0;
    tag[now<<1]+=tmp; max[now<<1]+=tmp;
    tag[now<<1|1]+=tmp; max[now<<1|1]+=tmp;
    return ;
}

void modify(int now,int tl,int tr,int l,int r,int v) {
    if (tl==l&&tr==r) {
        max[now]+=v;
        tag[now]+=v;
        return ;
    }
    int mid=(tl+tr)>>1;
    push_down(now);
    if (r<=mid) modify(now<<1,tl,mid,l,r,v);
    else if (l>mid) modify(now<<1|1,mid+1,tr,l,r,v);
    else {
        modify(now<<1,tl,mid,l,mid,v);
        modify(now<<1|1,mid+1,tr,mid+1,r,v);
    }
    max[now]=std:: max(max[now<<1],max[now<<1|1]);
}

int query(int now,int tl,int tr,int l,int r) {
    if (tl==l&&tr==r) return max[now];
    int mid=(tl+tr)>>1;
    push_down(now);
    if (r<=mid) return query(now<<1,tl,mid,l,r);
    if (l>mid) return query(now<<1|1,mid+1,tr,l,r);
    int qx=query(now<<1,tl,mid,l,mid);
    int qy=query(now<<1|1,mid+1,tr,mid+1,r);
    return std:: max(qx,qy);
}

bool cmp(line a,line b) {
    return a.v<b.v;
}

int main(void) {
    int n=read(),m=read();
    rep(i,1,n) {
        int x=read(),y=read();
        l[i]=(line) {x,y,y-x};
        b[i*2-1]=x; b[i*2]=y;
    }
    std:: sort(b+1,b+n*2+1);
    int size=std:: unique(b+1,b+n*2+1)-b-1;
    rep(i,1,n) {
        l[i].l=std:: lower_bound(b+1,b+size+1,l[i].l)-b;
        l[i].r=std:: lower_bound(b+1,b+size+1,l[i].r)-b;
    }
    std:: sort(l+1,l+n+1,cmp);
    int last=1,ans=INF;
    rep(i,1,n) {
        modify(1,1,size,l[i].l,l[i].r,1);
        while (max[1]>=m) {
            ans=std:: min(ans,l[i].v-l[last].v);
            modify(1,1,size,l[last].l,l[last].r,-1);
            last++;
        }
    }
    if (ans==INF) ans=-1;
    printf("%d\n", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值