题目

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

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

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

输入格式

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

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

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

输出格式

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

输入样例

6 3

3 5

1 2

3 4

2 2

1 5

1 4

输出样例

2

题解

比较容易想到,如果我们对所选的区间都+1,那么一定存在某个位置的值>=m

先对区间离散化

这样我们可以得到一个\(O(n^3)\)的算法

区间修改求最值,离散化后用线段树优化,可以做到\(O(n^2logn)\)

为了进一步减小一个n,我们将区间按区间长度排序

从小开始逐个加入线段树中,直到出现>=m的位置,再尝试从小开始从线段树中删除,直至满足>=m时再移动右端点

可以证明这样做的正确性

因为区间过多不影响存在某位置>=m,通过不断移动右端点,有解一定可以判出

设当前解为len,如果不移动左端点,右端点移动的结果一定不会比len要小

所以在满足条件的情况下应尽量移动左端点

\(O(nlogn)\)

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
#define ls (u << 1)
#define rs (u << 1 | 1)
using namespace std;
const int maxn = 1000005,maxm = 500005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
return out * flag;
}
struct node{int l,r;}e[maxm];
int b[maxn],bi,tot = 1,n,m,ans = INF;
int mx[4 * maxn],tag[4 * maxn];
inline bool operator <(const node& a,const node& x){
return (b[a.r] - b[a.l]) < (b[x.r] - b[x.l]);
}
int getn(int x){return lower_bound(b + 1,b + 1 + tot,x) - b;}
void pd(int u){
if (tag[u]){
mx[ls] += tag[u]; mx[rs] += tag[u];
tag[ls] += tag[u]; tag[rs] += tag[u];
tag[u] = 0;
}
}
void modify(int u,int l,int r,int L,int R,int x){
if (l >= L && r <= R){
mx[u] += x; tag[u] += x;
return;
}
pd(u);
int mid = l + r >> 1;
if (mid >= L) modify(ls,l,mid,L,R,x);
if (mid < R) modify(rs,mid + 1,r,L,R,x);
mx[u] = max(mx[ls],mx[rs]);
}
int main(){
n = read(); m = read();
for (int i = 1; i <= n; i++)
b[++bi] = e[i].l = read(),b[++bi] = e[i].r = read();
sort(b + 1,b + 1 + bi);
for (int i = 2; i <= bi; i++) if (b[i] != b[tot]) b[++tot] = b[i];
for (int i = 1; i <= n; i++)
e[i].l = getn(e[i].l),e[i].r = getn(e[i].r);
sort(e + 1,e + 1 + n);
modify(1,1,tot,e[1].l,e[1].r,1);
int l = 1,r = 1,L,R;
L = R = b[e[1].r] - b[e[1].l];
if (mx[1] >= m) ans = min(ans,R - L);
while (r <= n){
while (mx[1] >= m && l < r){
modify(1,1,tot,e[l].l,e[l].r,-1);
l++;
L = b[e[l].r] - b[e[l].l];
if (mx[1] >= m) ans = min(ans,R - L);
}
r++;
if (r > n) break;
R = b[e[r].r] - b[e[r].l];
modify(1,1,tot,e[r].l,e[r].r,1);
if (mx[1] >= m) ans = min(ans,R - L);
}
printf("%d\n",ans == INF ? -1 : ans);
return 0;
}

NOI2016 区间 【线段树】的更多相关文章

  1. [NOI2016]区间 线段树

    [NOI2016]区间 LG传送门 考虑到这题的代价是最长边减最短边,可以先把边按长度排个序,双指针维护一个尺取的过程,如果存在包含某个点的区间数\(\ge m\),就更新答案并把左指针右移,这样做的 ...

  2. Luogu P1712 [NOI2016]区间(线段树)

    P1712 [NOI2016]区间 题意 题目描述 在数轴上有 \(N\) 个闭区间 \([l_1,r_1],[l_2,r_2],...,[l_n,r_n]\) .现在要从中选出 \(M\) 个区间, ...

  3. UOJ222 NOI2016 区间 线段树+FIFO队列

    首先将区间按长度排序后离散化端点(这里的“长度”指的是离散化之前区间的实际长度) 然后模拟一个队列,区间按排好的顺序依次进入,直到某个点被覆盖了M次.之后依次出队,直到所有点都被覆盖小于M次 修改和询 ...

  4. BZOJ.4653.[NOI2016]区间(线段树)

    BZOJ4653 UOJ222 考虑二分.那么我们可以按区间长度从小到大枚举每个区间,对每个区间可以得到一个可用区间长度范围. 我们要求是否存在一个点被这些区间覆盖至少\(m\)次.这可以用线段树区间 ...

  5. BZOJ4653 [NOI2016]区间 [线段树,离散化]

    题目传送门 区间 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就 ...

  6. BZOJ4653: [Noi2016]区间(线段树 双指针)

    题意 题目链接 Sol 按照dls的说法,一般这一类的题有两种思路,一种是枚举一个点\(M\),然后check它能否成为答案.但是对于此题来说好像不好搞 另一种思路是枚举最小的区间长度是多少,这样我们 ...

  7. 洛谷$P1712\ [NOI2016]$区间 线段树

    正解:线段树 解题报告: 传送门$QwQ$ $umm$很久以前做的了来补个题解$QwQ$ 考虑给每个区间按权值($r-l$从大往小排序,依次加入,然后考虑如果有一个位置被覆盖次数等于$m$了就可以把权 ...

  8. BZOJ4653:[NOI2016]区间(线段树)

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

  9. hdu 1540 Tunnel Warfare (区间线段树(模板))

    http://acm.hdu.edu.cn/showproblem.php?pid=1540 Tunnel Warfare Time Limit: 4000/2000 MS (Java/Others) ...

  10. BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)

    题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...

随机推荐

  1. [课堂总结]C++课堂总结(二)

    近期的面向对象程序设计的不容易记忆或者理解的东西进行一个总结,以后忘记了可以常来看下,C++是个很重要的东西,很多领域都用得到,加油,特种兵! 浅拷贝构造.深拷贝构造 浅拷贝构造是系统默认的拷贝构造函 ...

  2. 使用控件的Tag属性传递信息

    实现效果: 知识运用: Control类的Tag属性 //获取或设置包含 有关控件的数据的对象 public object Tag {get;set;} 实现代码: private void Form ...

  3. 1968: C/C++经典程序训练6---歌德巴赫猜想的证明

    1968: C/C++经典程序训练6---歌德巴赫猜想的证明 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 1165  Solved: 499[Submi ...

  4. 分类回归树(CART)

    概要 本部分介绍 CART,是一种非常重要的机器学习算法.   基本原理   CART 全称为 Classification And Regression Trees,即分类回归树.顾名思义,该算法既 ...

  5. Sublime +Markdown+OmniMarkupPreviewer 搭建实时预览的markdown编辑器

    浏览器实时预览 <meta http-equiv="refresh" content="0.1"> auto save 的配置 {"aut ...

  6. ios 设计模式总结

    设计模式:备注:消息传递模型(Message Passing)是Objective-C语言的核心机制.在Objective-C中,没有方法调用这种说法,只有消息传递.在C++或Java中调用某个类的方 ...

  7. Kenneth A.Lambert著的数据结构(用python语言描述)的第一章课后编程答案

    第6题:工资部门将每个支付周期的雇员信息的列表保存到一个文本文件, 每一行的格式:<last name><hourly wage><hours worked> 编写 ...

  8. bzoj4666 小z的胡话

    题目描述: bz 题解: 乱搞好题哇. 众所周知斐波那契数列是有循环节的. 我们可以搞出在模$10^x$下与所给得数同余的集合,那么在模$10^{x+1}$下,同余集合一定是原集合及循环若干循环节的大 ...

  9. sphinx 快速使用

    建立配置文件 例可以参照之前的模板新建一个配置文件 sphinx/etc目录 #MySQL数据源配置,详情请查看:http://www.coreseek.cn/products-install/mys ...

  10. 【laravel】Laravel 5 TokenMismatchException on PHP 5.6.9

    When I realized this was only happening in IE and Chrome, but not Firefox, it led me to the fix. The ...