题解【bzoj4653 [NOI2016] 区间】
先按照长度排个序,然后依次添加区间。什么是添加?设这个区间是\([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] 区间】的更多相关文章
- [BZOJ4653][NOI2016]区间 贪心+线段树
4653: [Noi2016]区间 Time Limit: 60 Sec Memory Limit: 256 MB Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],. ...
- BZOJ4653: [Noi2016]区间
传送门 UOJ上卡掉一个点,COGS上卡掉两个点..弃疗,不改了,反正BZOJ上过啦hhh 先把区间按长度递增排序.然后每次用线段树维护区间最大覆盖次数,用一个指针随便扫扫就行了. //NOI 201 ...
- BZOJ4653 [NOI2016] 区间 【线段树】
题目分析: 首先思考一个二分答案的做法.我们可以注意到答案具有单调性,所以可以二分答案. 假设当前二分的答案是$ k $.那么按照大小顺序插入每个区间,同时在末端删除会对答案产生影响的区间.这里不妨用 ...
- 2018.08.17 bzoj4653: [Noi2016]区间(线段树+尺取法)
传送门 将坐标离散化之后直接用尺取法(双指针)+线段树维护. 其实就是说只要目前所有点的被覆盖次数是大于等于m的就移动左指针删除区间更新答案,否则移动右指针加入区间更新答案. 话说忘记排序以及建树的时 ...
- BZOJ4653:[NOI2016]区间(线段树)
Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x ...
- BZOJ4653 [NOI2016]区间 [线段树,离散化]
题目传送门 区间 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就 ...
- 【题解】NOI2016区间
Two - pointer 第一题…… 大概就是对于一段连续的区间求解,使用两个指针不断卡区间的长度直到区间不满足条件吧. 这题只要对区间以长度从小到大排一下序,然后使用两个指针指向区间.线段树维护被 ...
- BZOJ4653: [Noi2016]区间(线段树 双指针)
题意 题目链接 Sol 按照dls的说法,一般这一类的题有两种思路,一种是枚举一个点\(M\),然后check它能否成为答案.但是对于此题来说好像不好搞 另一种思路是枚举最小的区间长度是多少,这样我们 ...
- 【BZOJ4653】[Noi2016]区间 双指针法+线段树
[BZOJ4653][Noi2016]区间 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含 ...
随机推荐
- spark-submit配置说明
<Spark 官方文档>Spark配置 spark-1.6.0 原文地址 Spark配置 Spark有以下三种方式修改配置: Spark properties (Spark属性)可以控制绝 ...
- appcrawler遍历工具常用方法
Usage: appcrawler [options] -a, --app <value> Android或者iOS的文件地址, 可以是网络地址, 赋值给appium的app选项 -c, ...
- git branch 分支与合并
在使用 git 进行分支开发与合并的时候需要用到这些命令.其他基本 git 命令参考 Git 简易食用指南 git branch 查看分支 git branch 查看当前分支情况 创建分支 git b ...
- 从零开始的Python学习Episode 2——运算符与while循环
一.算术运算符 加法:+,减法:-,乘法*,除法/,整除(地板除)//,取余%,乘方**. 二.逻辑运算符 且:and,或:or,非:not 优先级:not>and>or 短路原则: 对 ...
- LeetCode 95——不同的二叉搜索树 II
1. 题目 2. 解答 以 \(1, 2, \cdots, n\) 构建二叉搜索树,其中,任意数字都可以作为根节点来构建二叉搜索树.当我们将某一个数字作为根节点后,其左边数据将构建为左子树,右边数据将 ...
- python中spilt()函数和os.path.spilt()函数区别
Python中有split()和os.path.split()两个函数: split():拆分字符串.通过指定分隔符对字符串进行切片,并返回分割后的字符串列表. os.path.split():将文件 ...
- Ansys Workbench热流固耦合仿真配置
1.Fluent-Thermal-Structural瞬态分析 此模块连接在fluent已实现流体和固体的热流耦合,传递至thermal实际上只是将流体表面温度作为热载荷施加在固体的液体通道表面,极大 ...
- 【week6】用户数
小组名称:nice! 小组成员:李权 于淼 杨柳 刘芳芳 项目内容:约跑app alpha发布48小时以后用户数如何,是否达到预期目标,为什么,是否需要改进,如何改进(或理性估算). 首先我们的app ...
- CSS设计指南之一 HTML标记与文档结构
HTML标记与文档结构 之所以从HTML讲起,是因为CSS的用途就是为HTML标记添加样式. 1.1 HTML标记基础 对于每个包含内容的元素,根据它所包含的内容是不是文本,有两种不同的方式给它们加标 ...
- ResultSet 可滚动性和可更新性
JDBC 2.0 API 为结果集增加了两个新的基本能力:可滚动性和可更新性,我想肯定满足了你的要求.在滚动结果集中可用的方法有: rs.previous();//向前滚动 rs.next();//向 ...