先按照长度排个序,然后依次添加区间。什么是添加?设这个区间是\([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\),开线段树是要离散化的。上代码:

  1. #include <bits/stdc++.h>
  2. #define INF 1000000001
  3. using namespace std;
  4. const int N = 500500;
  5. int n, m, cnt, tot, ans = INF;
  6. struct Seg {
  7. int l, r, len;
  8. bool operator < (const Seg &x) const {
  9. return len < x.len;
  10. }
  11. }a[N];
  12. struct KEY {
  13. int d, id, se;
  14. }key[N * 2];
  15. inline bool cmp1(KEY x, KEY y) {
  16. return x.d < y.d;
  17. }
  18. inline bool cmp2(KEY x, KEY y) {
  19. return x.id < y.id;
  20. }
  21. struct node {
  22. int left, right, Max, lazy;
  23. node *ch[2];
  24. }pool[N * 4], *root;
  25. inline void pushup(node *r) {
  26. r->Max= max(r->ch[0]->Max, r->ch[1]->Max);
  27. }
  28. inline void pushdown(node *r) {
  29. if(!r->lazy) return ;
  30. r->Max += r->lazy;
  31. if(r->ch[0]) r->ch[0]->lazy += r->lazy;
  32. if(r->ch[1]) r->ch[1]->lazy += r->lazy;
  33. r->lazy = 0; return ;
  34. }
  35. inline void build(node *r, int left, int right) {
  36. r->left = left, r->right = right;
  37. if(left == right) return ;
  38. int mid = (left + right) >> 1;
  39. node *lson = &pool[++cnt], *rson = &pool[++cnt];
  40. r->ch[0] = lson, r->ch[1] = rson;
  41. build(lson, left, mid), build(rson, mid + 1, right);
  42. }
  43. inline void change(node *r, int left, int right, int d) {
  44. if(r->left == left && r->right == right) {
  45. r->lazy += d; return ;
  46. }
  47. pushdown(r);
  48. if(r->ch[0]->right >= right) change(r->ch[0], left, right, d);
  49. else if(r->ch[1]->left <= left) change(r->ch[1], left, right, d);
  50. else change(r->ch[0], left, r->ch[0]->right, d), change(r->ch[1], r->ch[1]->left, right, d);
  51. pushdown(r->ch[0]), pushdown(r->ch[1]), pushup(r);
  52. }
  53. int main() {
  54. scanf("%d%d", &n, &m);
  55. for(int i = 1; i <= n; i++) {
  56. scanf("%d%d", &a[i].l, &a[i].r);
  57. a[i].len = a[i].r - a[i].l;
  58. key[++tot].d = a[i].l, key[tot].id = tot;
  59. key[++tot].d = a[i].r, key[tot].id = tot;
  60. }
  61. sort(key + 1, key + tot + 1, cmp1);
  62. key[0].d = -1; key[0].se = 0;
  63. for(int i = 1; i <= tot; i++)
  64. if(key[i].d == key[i - 1].d)
  65. key[i].se = key[i - 1].se;
  66. else key[i].se = key[i - 1].se + 1;
  67. sort(key + 1, key + tot + 1, cmp2);
  68. for(int i = 1; i <= n; i++)
  69. a[i].l = key[i * 2 - 1].se, a[i].r = key[i * 2].se;
  70. sort(a + 1, a + n + 1);
  71. build(root = &pool[0], 1, 2 * n + 1);
  72. int pos = 1;
  73. change(root, a[1].l, a[1].r, 1);
  74. if(m == 1) ans = 0;
  75. for(int i = 2; i <= n; i++) {
  76. change(root, a[i].l, a[i].r, 1);
  77. while(root->Max >= m) {
  78. change(root, a[pos].l, a[pos].r, -1);
  79. ans = min(ans, a[i].len - a[pos].len);
  80. pos++;
  81. }
  82. }
  83. if(ans == INF) ans = -1;
  84. printf("%d\n", ans);
  85. return 0;
  86. }

题解【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. Hbase restFul API

    获取hbase版本 curl -vi -X GET -H "Accept: text/xml" http://10.8.4.46:20550/version/cluster1.2. ...

  2. ionic typescript--验证码发送倒计时功能

    1.新建页面 ionic g page forget   2.mode.html文件 <ion-item> <ion-input clearInput [(ngModel)]='co ...

  3. 常用正则表达式,你要的都在这里(校验字符,数字,特殊需求qq,电话等)

    一.校验数字的表达式 1 数字:^[0-9]*$ 2 n位的数字:^\d{n}$ 3 至少n位的数字:^\d{n,}$ 4 m-n位的数字:^\d{m,n}$ 5 零和非零开头的数字:^(0|[1-9 ...

  4. TCP系列25—重传—15、DSACK虚假重传探测

    一.DSACK介绍 RFC2883通过指定使用SACK来指示接收端的重复包(duplicate packet)扩展了RFC2018对SACK选项的定义(SACK选项的介绍和示例参考前面内容).RFC2 ...

  5. C++ 普通函数和虚函数调用的区别

    引出:写个类A,声明类A指针指向NULL,调用类A的方法会有什么后果,编译通过吗,运行会通过吗? #include<stdio.h> #include<iostream> us ...

  6. python爬虫-使用xpath方法

    #coding=utf-8 import re from lxml import etree import requests response = requests.get("http:// ...

  7. oracle的SQL语句中的(+)是干什么用的?

    Oracle中的(+) 是外连接,如果在等号的左边就是左连接 和如果在等号的右边就是右连接 和left join ,right join 比较相似.....where sn (+) ='5620030 ...

  8. InnoDB,select为啥会阻塞insert?

    MySQL的InnoDB的细粒度行锁,是它最吸引人的特性之一. 但是,如<InnoDB,5项最佳实践>所述,如果查询没有命中索引,也将退化为表锁. InnoDB的细粒度锁,是实现在索引记录 ...

  9. HTML5拖拽表格中单元格间的数据库

    效果图:

  10. hdu 1528 Card Game Cheater (二分匹配)

    Card Game Cheater Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...