先按照长度排个序,然后依次添加区间。什么是添加?设这个区间是\([l,r]\),添加就是把\(a_l,a_{l+1},a_{l+2},{...},a_{r}\)都加上\(1\),其中\(a_i\)表示第\(i\)个位置被几个区间覆盖。拿走一个区间的含义就是把它们都减\(1\)。这个过程很显然可以用线段树维护。

如果在添加到一个区间 \(i\) 时,有一个点被区间覆盖了\(M\)次,那么先更新答案,再把前面的加入过的区间一直拿直到没有一个点被覆盖\(M\)次。如何判断有没有点被覆盖\(M\)次?因为是一个一个区间加的,所以只用维护一个\(a_i\)的最大值,看他是否\(=M\)就行了。

什么叫再把前面的加入过的区间一直拿直到没有一个点被覆盖\(M\)次

比如你一直添加区间到第\(5\)个,此时有一个点被覆盖了\(M\)次。这时你就将第一个区间拿出,如果此时依然有有一个点被覆盖了\(M\)次,那么你就拿走第二个...

这个过程就好比一个队列,可以从后面添加区间达到一个点被覆盖了\(M\)次;从前面弹出区间直到没有一个点被覆盖了\(M\)次。

差不多就是这样,还有注意一下\(l_i,r_i \leq 10^9\),开线段树是要离散化的。上代码:

#include <bits/stdc++.h>
#define INF 1000000001
using namespace std;
const int N = 500500;
int n, m, cnt, tot, ans = INF;
struct Seg {
int l, r, len;
bool operator < (const Seg &x) const {
return len < x.len;
}
}a[N];
struct KEY {
int d, id, se;
}key[N * 2];
inline bool cmp1(KEY x, KEY y) {
return x.d < y.d;
}
inline bool cmp2(KEY x, KEY y) {
return x.id < y.id;
}
struct node {
int left, right, Max, lazy;
node *ch[2];
}pool[N * 4], *root;
inline void pushup(node *r) {
r->Max= max(r->ch[0]->Max, r->ch[1]->Max);
}
inline void pushdown(node *r) {
if(!r->lazy) return ;
r->Max += r->lazy;
if(r->ch[0]) r->ch[0]->lazy += r->lazy;
if(r->ch[1]) r->ch[1]->lazy += r->lazy;
r->lazy = 0; return ;
}
inline void build(node *r, int left, int right) {
r->left = left, r->right = right;
if(left == right) return ;
int mid = (left + right) >> 1;
node *lson = &pool[++cnt], *rson = &pool[++cnt];
r->ch[0] = lson, r->ch[1] = rson;
build(lson, left, mid), build(rson, mid + 1, right);
}
inline void change(node *r, int left, int right, int d) {
if(r->left == left && r->right == right) {
r->lazy += d; return ;
}
pushdown(r);
if(r->ch[0]->right >= right) change(r->ch[0], left, right, d);
else if(r->ch[1]->left <= left) change(r->ch[1], left, right, d);
else change(r->ch[0], left, r->ch[0]->right, d), change(r->ch[1], r->ch[1]->left, right, d);
pushdown(r->ch[0]), pushdown(r->ch[1]), pushup(r);
}
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;
key[++tot].d = a[i].l, key[tot].id = tot;
key[++tot].d = a[i].r, key[tot].id = tot;
}
sort(key + 1, key + tot + 1, cmp1);
key[0].d = -1; key[0].se = 0;
for(int i = 1; i <= tot; i++)
if(key[i].d == key[i - 1].d)
key[i].se = key[i - 1].se;
else key[i].se = key[i - 1].se + 1;
sort(key + 1, key + tot + 1, cmp2);
for(int i = 1; i <= n; i++)
a[i].l = key[i * 2 - 1].se, a[i].r = key[i * 2].se;
sort(a + 1, a + n + 1);
build(root = &pool[0], 1, 2 * n + 1);
int pos = 1;
change(root, a[1].l, a[1].r, 1);
if(m == 1) ans = 0;
for(int i = 2; i <= n; i++) {
change(root, a[i].l, a[i].r, 1);
while(root->Max >= m) {
change(root, a[pos].l, a[pos].r, -1);
ans = min(ans, a[i].len - a[pos].len);
pos++;
}
}
if(ans == INF) ans = -1;
printf("%d\n", ans);
return 0;
}

题解【bzoj4653 [NOI2016] 区间】的更多相关文章

  1. [BZOJ4653][NOI2016]区间 贪心+线段树

    4653: [Noi2016]区间 Time Limit: 60 Sec  Memory Limit: 256 MB Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],. ...

  2. BZOJ4653: [Noi2016]区间

    传送门 UOJ上卡掉一个点,COGS上卡掉两个点..弃疗,不改了,反正BZOJ上过啦hhh 先把区间按长度递增排序.然后每次用线段树维护区间最大覆盖次数,用一个指针随便扫扫就行了. //NOI 201 ...

  3. BZOJ4653 [NOI2016] 区间 【线段树】

    题目分析: 首先思考一个二分答案的做法.我们可以注意到答案具有单调性,所以可以二分答案. 假设当前二分的答案是$ k $.那么按照大小顺序插入每个区间,同时在末端删除会对答案产生影响的区间.这里不妨用 ...

  4. 2018.08.17 bzoj4653: [Noi2016]区间(线段树+尺取法)

    传送门 将坐标离散化之后直接用尺取法(双指针)+线段树维护. 其实就是说只要目前所有点的被覆盖次数是大于等于m的就移动左指针删除区间更新答案,否则移动右指针加入区间更新答案. 话说忘记排序以及建树的时 ...

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

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

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

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

  7. 【题解】NOI2016区间

    Two - pointer 第一题…… 大概就是对于一段连续的区间求解,使用两个指针不断卡区间的长度直到区间不满足条件吧. 这题只要对区间以长度从小到大排一下序,然后使用两个指针指向区间.线段树维护被 ...

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

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

  9. 【BZOJ4653】[Noi2016]区间 双指针法+线段树

    [BZOJ4653][Noi2016]区间 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含 ...

随机推荐

  1. 【Python 开发】第三篇:python 实用小工具

    一.快速启动一个web下载服务器 官方文档:https://docs.python.org/2/library/simplehttpserver.html 1)web服务器:使用SimpleHTTPS ...

  2. day-18 滑动平均模型测试样例

    为了使训练模型在测试数据上有更好的效果,可以引入一种新的方法:滑动平均模型.通过维护一个影子变量,来代替最终训练参数,进行训练模型的验证. 在tensorflow中提供了ExponentialMovi ...

  3. 从oracle导入hive

    sqoop import --connect jdbc:oracle:thin:@10.39.1.43:1521/rcrm --username bi_query --password ####### ...

  4. HADOOP docker(四):安装hive

    1.hive简介2.安装hive2.1 环境准备2.1.1 下载安装包2.1.2 设置hive用户的环境变量2.1.3 hive服务端配置文件2.1.4 hive客户端配置文件2.1.4 分发hive ...

  5. nodejs笔记--Events篇(二)

    常用事件 /* 调用events模块,获取events.EventEmitter对象 */ var EventEmitter = require('events').EventEmitter; var ...

  6. Mr. Frog’s Game(模拟连连看)

    Description One day, Mr. Frog is playing Link Game (Lian Lian Kan in Chinese). In this game, if you ...

  7. 算法与数据结构实验题 4.1 伊姐姐数字 game

    ★实验任务 伊姐姐热衷于各类数字游戏,24 点.2048.数独等轻轻松松毫无压力.一 日,可爱的小姐姐邀请伊姐姐一起玩一种简单的数字 game,游戏规则如下: 一开始桌上放着 n 张数字卡片,从左到右 ...

  8. Ubuntu下FileZilla的安装

    FileZilla是一个免费而且开源的FTP客户端软件,共有两种版本:客户端版本.服务器版本.FileZilla有条理的界面和管理多站点的简化方式使得FileZilla Client成为一个方便高效的 ...

  9. 一个例子说明mouseover事件与mouseenter事件的区别

    <html> <head> <meta charset="UTF-8"> <title>haha</title> < ...

  10. 移动端的picker参考vux

    参考vux移动端的ui组件,做了一个picker,测试在微信,uc主流浏览器能够正常工作.而在华为浏览器根本不能使用.而测试了vux的原有picker组件,发现在华为自带浏览器中,效果依然能够实现. ...