Luogu1712 [NOI2016] 区间

原题链接:https://www.luogu.com.cn/problem/P1712

区间

题目描述

在数轴上有 n n n 个闭区间从 1 1 1 n n n 编号,第 i i i 个闭区间为 [ l i , r i ] [l_i,r_i] [li,ri]

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

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

区间 [ l i , r i ] [l_i,r_i] [li,ri] 的长度定义为 ( r i − l i ) (r_i-l_i) (rili) ,即等于它的右端点的值减去左端点的值。

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

输入格式

第一行包含两个整数,分别代表 n n n m m m

2 2 2 到第 ( n + 1 ) (n + 1) (n+1) 行,每行两个整数表示一个区间,第 ( i + 1 ) (i + 1) (i+1) 行的整数 l i , r i l_i, r_i li,ri 分别代表第 i i i 个区间的左右端点。

输出格式

输出一行一个整数表示答案。

输入输出样例

输入 #1
6 3
3 5
1 2
3 4
2 2
1 5
1 4
输出 #1
2

说明/提示

样例输入输出 1 解释

在这里插入图片描述

数据规模与约定

本题共 20 个测试点,各测试点信息如下表。

测试点编号 n = n= n= m = m= m= l i , r i l_i,r_i li,ri
1 20 20 20 9 9 9 0 ≤ l i ≤ r i ≤ 100 0 \le l_i \le r_i \le 100 0liri100
2 20 20 20 10 10 10 0 ≤ l i ≤ r i ≤ 100 0 \le l_i \le r_i \le 100 0liri100
3 19 19 19 3 3 3 0 ≤ l i ≤ r i ≤ 100000 0 \le l_i \le r_i \le 100000 0liri100000
4 200 200 200 3 3 3 0 ≤ l i ≤ r i ≤ 100000 0 \le l_i \le r_i \le 100000 0liri100000
5 1000 1000 1000 2 2 2 0 ≤ l i ≤ r i ≤ 100000 0 \le l_i \le r_i \le 100000 0liri100000
6 2000 2000 2000 2 2 2 0 ≤ l i ≤ r i ≤ 100000 0 \le l_i \le r_i \le 100000 0liri100000
7 199 199 199 60 60 60 0 ≤ l i ≤ r i ≤ 5000 0 \le l_i \le r_i \le 5000 0liri5000
8 200 200 200 50 50 50 0 ≤ l i ≤ r i ≤ 5000 0 \le l_i \le r_i \le 5000 0liri5000
9 200 200 200 50 50 50 0 ≤ l i ≤ r i ≤ 1 0 9 0 \le l_i \le r_i \le 10^9 0liri109
10 1999 1999 1999 500 500 500 0 ≤ l i ≤ r i ≤ 5000 0 \le l_i \le r_i \le 5000 0liri5000
11 2000 2000 2000 400 400 400 0 ≤ l i ≤ r i ≤ 5000 0 \le l_i \le r_i \le 5000 0liri5000
12 2000 2000 2000 500 500 500 0 ≤ l i ≤ r i ≤ 1 0 9 0 \le l_i \le r_i \le 10^9 0liri109
13 30000 30000 30000 2000 2000 2000 0 ≤ l i ≤ r i ≤ 100000 0 \le l_i \le r_i \le 100000 0liri100000
14 40000 40000 40000 1000 1000 1000 0 ≤ l i ≤ r i ≤ 100000 0 \le l_i \le r_i \le 100000 0liri100000
15 50000 50000 50000 15000 15000 15000 0 ≤ l i ≤ r i ≤ 100000 0 \le l_i \le r_i \le 100000 0liri100000
16 100000 100000 100000 20000 20000 20000 0 ≤ l i ≤ r i ≤ 100000 0 \le l_i \le r_i \le 100000 0liri100000
17 200000 200000 200000 20000 20000 20000 0 ≤ l i ≤ r i ≤ 1 0 9 0 \le l_i \le r_i \le 10^9 0liri109
18 300000 300000 300000 50000 50000 50000 0 ≤ l i ≤ r i ≤ 1 0 9 0 \le l_i \le r_i \le 10^9 0liri109
19 400000 400000 400000 90000 90000 90000 0 ≤ l i ≤ r i ≤ 1 0 9 0 \le l_i \le r_i \le 10^9 0liri109
20 500000 500000 500000 200000 200000 200000 0 ≤ l i ≤ r i ≤ 1 0 9 0 \le l_i \le r_i \le 10^9 0liri109

对于全部的测试点,保证 1 ≤ m ≤ n 1 ≤ m ≤ n , 1 ≤ n ≤ 5 × 1 0 5 1 \leq m \leq n1≤m≤n,1 \leq n \leq 5 \times 10^5 1mn1mn1n5×105 1 ≤ m ≤ 2 × 1 0 5 1 \leq m \leq 2 \times 10^5 1m2×105 0 ≤ l i ≤ r i ≤ 1 0 9 0 \leq l_i \leq r_i \leq 10^9 0liri109

题解

本来的想法是,把所有区间按长度排序,然后二分答案,在不超过二分出的长度的情况下伸缩区间,用线段树维护个支持区间加的最大值,只要有的点权值 ≥ m \ge m m就可行。

由于二分套线段树复杂度大概是 O ( n l o g 2 2 n ) O(nlog_2^2n) O(nlog22n)的,不出意外的 T L E 80 \mathcal{TLE}80 TLE80滚粗了。

仔细思考发现,实际上根本不需要二分,伸缩区间的时候存在全局最大值 ≥ m \ge m m直接去更新答案就好了。

代码

记得横坐标需要离散化,同时判断 − 1 -1 1的情况,然后线段树要开八倍,因为一个区间会有两个横坐标,需要多乘二。

#include<bits/stdc++.h>
#define ls v<<1
#define rs v<<1|1
using namespace std;
const int M=5e5+5;
struct node{
    
    int le,ri,mx,delta;}tree[M<<3];
struct Inter{
    
    int le,ri,len;}inter[M];
bool cmp(Inter a,Inter b){
    
    return a.len<b.len;};
int n,m,x[M<<1],tot,ans=INT_MAX;
void up(int v){
    
    tree[v].mx=max(tree[ls].mx,tree[rs].mx);}
void build(int v,int le,int ri)
{
    
    
    tree[v].le=x[le],tree[v].ri=x[ri];
    if(le==ri)return;
    int mid=le+ri>>1;
    build(ls,le,mid);build(rs,mid+1,ri);
}
void push(int v,int delta){
    
    tree[v].mx+=delta,tree[v].delta+=delta;}
void down(int v){
    
    if(tree[v].delta)push(ls,tree[v].delta),push(rs,tree[v].delta),tree[v].delta=0;}
void add(int v,int le,int ri,int delta)
{
    
    
    if(le<=tree[v].le&&tree[v].ri<=ri){
    
    push(v,delta);return;}
    down(v);
    if(le<=tree[ls].ri)add(ls,le,ri,delta);
    if(tree[rs].le<=ri)add(rs,le,ri,delta);
    up(v);
}
void in()
{
    
    
    scanf("%d%d",&n,&m);
    for(int i=1,a,b;i<=n;++i)scanf("%d%d",&a,&b),inter[i]=(Inter){
    
    a,b,b-a},x[++tot]=a,x[++tot]=b;
}
void ac()
{
    
    
    sort(inter+1,inter+1+n,cmp);
    sort(x+1,x+1+tot);
    tot=unique(x+1,x+1+tot)-1-x;
    build(1,1,tot);
    for(int le=1,ri=1;;)
    {
    
    
        for(;tree[1].mx<m&&ri<=n;++ri,add(1,inter[ri].le,inter[ri].ri,1));
        if(tree[1].mx<m)break;
        for(;tree[1].mx>=m;++le,add(1,inter[le].le,inter[le].ri,-1));
        ans=min(ans,inter[ri].len-inter[le].len);
    }
    printf("%d\n",ans==INT_MAX?-1:ans);
}
int main()
{
    
    
    in(),ac();
    system("pause");
}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/113854133