[Noi2016]区间[离散化+线段树维护+决策单调性]

4653: [Noi2016]区间

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 621  Solved: 329
[Submit][Status][Discuss]

Description

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

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

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

Input

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

接下来 n行,每行表示一个区间,包含用空格隔开的两个整数 li 和 ri 为该区间的左右端点。

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

Output

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

Sample Input

6 3
3 5
1 2
3 4
2 2
1 5
1 4

Sample Output

2

HINT

Source

  首先我们考虑暴力怎么做,按长度排序之后,我们容易发现,如果枚举一个区间作为左端点,一个区间作为右端点,那么我们就是求只在这个区间中选取的答案。

  我们把这一段的所有区间的对应的一段的经过次数都加一,最后只需check一下这一段中是否出现了一个被经过m次的点,一旦存在就说明,我们一定可以找到其中的mm个区间满足题目的要求,所以我们就可以确保在这个区间中能够选取m个区间并一定合法,就可以用右端点的那个区间长度-左端点的那个区间长度来更新答案。(并不关心具体选了哪些区间)

  上述做法的复杂度可以用线段树维护来做到n2logn。深入思考可以发现,其实右端点肯定是不降的,所以我们没必要再枚举一个右端点,只要用单调指针一直往后扫即可。总复杂度为:O(nlogn)。

  (引自 ljh2000

#include<cstdio>
#include<algorithm>
#include<cstring>
#define lch k<<1
#define rch k<<1|1
using namespace std;
const int N=1e6+5,M=N<<2;
const int inf=2e9;
int n,m,p,cnt,ans=inf;
int mx[M],tag[M];
struct node{int l,r,len;}a[N>>1];int b[N];
inline bool cmp(const node &x,const node &y){
    return x.len<y.len;
}
inline void opera(int k,int v){
    mx[k]+=v;
}
inline void pushdown(int k,int l,int r){
    if(!tag[k]) return ;
    tag[lch]+=tag[k];opera(lch,tag[k]);
    tag[rch]+=tag[k];opera(rch,tag[k]);
    tag[k]=0;
}
void change(int k,int l,int r,int x,int y,int v){
    if(l==x&&r==y){
        opera(k,v);
        tag[k]+=v;
        return ;
    }
    pushdown(k,l,r);
    int mid=(l+r)>>1;
    if(y<=mid) change(lch,l,mid,x,y,v);
    else if(x>mid) change(rch,mid+1,r,x,y,v);
    else change(lch,l,mid,x,mid,v),change(rch,mid+1,r,mid+1,y,v);
    mx[k]=max(mx[lch],mx[rch]);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i].l,&a[i].r),a[i].len=a[i].r-a[i].l;;
    for(int i=1;i<=n;i++) b[++cnt]=a[i].l,b[++cnt]=a[i].r;
    sort(a+1,a+n+1,cmp);
    sort(b+1,b+cnt+1);cnt=unique(b+1,b+cnt+1)-(b+1);
    for(int i=1;i<=n;i++){
        a[i].l=lower_bound(b+1,b+cnt+1,a[i].l)-b,
        a[i].r=lower_bound(b+1,b+cnt+1,a[i].r)-b;
    }
    int top=1;
    for(int i=1;i<=n;i++){
        for(;mx[1]<m&&top<=n;top++){
            change(1,1,cnt,a[top].l,a[top].r,1);
        }
        if(mx[1]==m) ans=min(ans,a[top-1].len-a[i].len);
        change(1,1,cnt,a[i].l,a[i].r,-1);
    }
    printf("%d\n",ans!=inf?ans:-1);
    return 0;
}
时间: 2024-10-02 03:10:14

[Noi2016]区间[离散化+线段树维护+决策单调性]的相关文章

POJ 2528 Mayor&#39;s posters 区间离散化线段树

点击打开链接 Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 45894   Accepted: 13290 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their elector

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

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

BZOJ_4653_[Noi2016]区间_线段树+离散化+双指针

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

hiho1079 : 离散化(线段树+区间离散化)

#1079 : 离散化 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho在回国之后,重新过起了朝7晚5的学生生活,当然了,他们还是在一直学习着各种算法~ 这天小Hi和小Ho所在的学校举办社团文化节,各大社团都在宣传栏上贴起了海报,但是贴来贴去,有些海报就会被其他社团的海报所遮挡住.看到这个场景,小Hi便产生了这样的一个疑问--最后到底能有几张海报还能被看见呢? 于是小Ho肩负起了解决这个问题的责任:因为宣传栏和海报的高度都是一样的,所以宣传栏可以被视作

ZOJ 2301 / HDU 1199 Color the Ball 离散化+线段树区间连续最大和

题意:给你n个球排成一行,初始都为黑色,现在给一些操作(L,R,color),给[L,R]区间内的求染上颜色color,'w'为白,'b'为黑.问最后最长的白色区间的起点和终点的位置. 解法:先离散化,为了防止离散后错误,不仅将L,R离散,还要加入L+1,L-1,R+1,R-1一起离散,这样就绝不会有问题了.然后建线段树,线段树维护四个值: 1.col  区间颜色  0 表示黑  1 表示白  -1表示无标记 2.maxi 区间内最大白区间的长度,由于白色用1表示,所以最大白区间的长度即为区间最

线段树维护区间最大子段和 枚举 HDU6638

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6638 题意:在一个二维坐标系上给你n(n<=2000)个点,点带有一个价值w(有正有负),点的坐标都在(-1e9,1e9)的范围之间,可任意用一个平行于坐标轴的矩形框住一片区域,求这片区域框住的点的价值和 分析:点的坐标范围太大,离散化应能想到.离散化后可以考虑枚举左边界,枚举左边界后按照横坐标的依次加点(以一列一列为单位),用线段树维护一列的最大子段和,每移动到新的一列,继续加点时,等价于向原先的

CCPC河南省赛B-树上逆序对| 离线处理|树状数组 + 线段树维护逆序对 + dfs序 + 离散化

B题地址:树上逆序对 有两个思路 方法一:线段树离线 + 树状数组或者线段树维护区间和 0:离散化,离线存储输入的operation操作序列. ①:先线段树在dfs序上离线处理好整一棵树:在dfs序上先查询"加入当前结点的逆序对权值和"并记录,再加入当前这个节点:dfs完毕后,就已经记录好每个结点的dfs序出入时间戳(转化成区间问题了)和每个 ②:使用树状数组或者新的线段树在dfs序上插入逆序对权值 为什么能这样呢?因为dfs序维护了每个结点遍历的顺序,每个结点的dfs序时间戳肯定比它

2016shenyang-1002-HDU5893-List wants to travel-树链剖分+线段树维护不同区间段个数

肯定先无脑树链剖分,然后线段树维护一段区间不同个数,再维护一个左右端点的费用. 线段树更新,pushDown,pushUp的时候要注意考虑链接位置的费用是否相同 还有就是树链剖分操作的时候,维护上一个更新的位置的费用. 总之就是出现区间合并,就考虑总数是否要减一 好想不好写 //场上根本写不完啊 1 /*--------------------------------------------------------------------------------------*/ 2 3 #inc

POJ 2528 Mayor&#39;s posters (离散化+线段树区间更新)

Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city council has finally decided to build an electoral wall for