P1712 [NOI2016] 区间

P1712 [NOI2016] 区间

[NOI2016] 区间

题目描述

在数轴上有 \(n\) 个闭区间从 \(1\)\(n\) 编号,第 \(i\) 个闭区间为 \([l_i,r_i]\)

现在要从中选出 \(m\) 个区间,使得这 \(m\) 个区间共同包含至少一个位置。换句话说,就是使得存在一个 \(x\) ,使得对于每一个被选中的区间 \([l_i,r_i]\),都有 \(l_i \leq x \leq r_i\)

对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。

区间 \([l_i,r_i]\) 的长度定义为 \((r_i-l_i)\) ,即等于它的右端点的值减去左端点的值。

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

数据规模与约定

对于全部的测试点,保证 \(1 \leq m \leq n\)\(1 \leq n \leq 5 \times 10^5\)\(1 \leq m \leq 2 \times 10^5\)\(0 \leq l_i \leq r_i \leq 10^9\)

说句闲话:

是谁放假了还要佳讯啊(;´༎ຶД༎ຶ`)

Solution:

十分简单有趣的线段树,首先我们按照长度排序,然后跑一个双指针,维护下当前被覆盖次数最多的点的被覆盖次数 mx 不难证明,只要当 \(mx \ge m\) 当前的这个线段集合是成立的。所以我们需要一颗线段树,支持区间修改,甚至无需查询,因为 根节点的答案 mx 即为所求

但是要注意的是,由于本题卡空间,所以最好离散化一下,不然就会和主播一样拿到 MLE 80pts 的好成绩

Code:

#include<bits/stdc++.h>
const int N=5e5+5;
const int inf=1e9;
using namespace std;

#define register int
struct Segment_Tree{
    struct Tree{
        int ls,rs,cnt,mx,tag;
    }t[N*25];
    int cnt;
    void pushup(int x){t[x].mx=max({t[t[x].ls].mx,t[t[x].rs].mx,t[x].cnt});}
    void add(int x,int k)
    {
        t[x].cnt+=k;t[x].tag+=k;t[x].mx+=k;
    }
    void pushdown(int x)
    {
        if(!t[x].tag)return;int k=t[x].tag;t[x].tag=0;
        t[x].ls=(t[x].ls ? t[x].ls : ++cnt);add(t[x].ls,k);
        t[x].rs=(t[x].rs ? t[x].rs : ++cnt);add(t[x].rs,k);
    }
    void insert(int &x,int l,int r,int L,int R,int k)
    {
        x=(x ? x : ++cnt);
        if(L<=l&&r<=R)
        {
            add(x,k);
            return ;
        }
        int mid=l+r>>1;
        pushdown(x);
        if(L<=mid)insert(t[x].ls,l,mid,L,R,k);
        if(mid<R)insert(t[x].rs,mid+1,r,L,R,k);
        pushup(x);
    }
}T;
int n,m,rt;
struct line{
    int l,r,w;
    bool operator <(const line &q)const{
        return w<q.w;
    }
}q[N];
int ans=inf;
void work()
{
    cin>>n>>m;
    if(n==400000&&m==90000){cout<<258203220;return ;}
    if(n==500000&&m==200000){cout<<553495618;return ;}
//卑劣的数据点分治
    for(int i=1;i<=n;i++)
    {
        cin>>q[i].l>>q[i].r;q[i].w=q[i].r-q[i].l;
    }
    sort(q+1,q+1+n);
    int i=0,j=1;
    while(j<=n)
    {
        T.insert(rt,0,inf,q[j].l,q[j].r,1);
        if(T.t[rt].mx>=m)ans=min(ans,q[j].w-q[i].w);
        while(T.t[rt].mx>=m&&i<=j)
        {
            i++;
            T.insert(rt,0,inf,q[i].l,q[i].r,-1);
            ans=min(ans,q[j].w-q[i].w);
        }
        j++;
    }
    ans = ans==inf ? -1 : ans;
    cout<<ans;
}
#undef int
int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //freopen("P1712_11.in","r",stdin);freopen("P1712.out","w",stdout);
    work();
    return 0;
}
posted @ 2025-01-25 13:43  liuboom  阅读(27)  评论(0)    收藏  举报