题意:给你n个区间,从中选择m个,使得它们有交,且最长与最短区间的差值最小。

解:这道题我想了好多的,nlog²n错的,nlogn错的,最后终于想出nlogn的了......

把区间按照长度排序,然后依次在线段树上加。

如果某一次等于m了,那么一个一个删,删到小于m的时候,更新答案。

证明:那些之前的区间如果想要成为答案,那么必须是和比当前这个还靠前的区间来组成。

这样的话当到这一个时,之前的要么被计算,要么不会更优。故可以删掉。

 #include <cstdio>
#include <algorithm> const int N = , INF = 0x3f3f3f3f; int sum[N << ], large[N << ], tag[N << ], X[N << ]; struct ITV {
int r, l, len;
inline bool operator <(const ITV &w) const {
return len < w.len;
}
}a[N]; inline void pushup(int o) {
int ls = o << ;
int rs = ls | ;
sum[o] = sum[ls] + sum[rs];
large[o] = std::max(large[ls], large[rs]);
return;
} inline void pushdown(int l, int r, int o) {
if(tag[o]) {
int ls = o << ;
int rs = ls | ;
int mid = (l + r) >> ;
tag[ls] += tag[o];
tag[rs] += tag[o];
sum[ls] += (mid - l + ) * tag[o];
sum[rs] += (r - mid) * tag[o];
large[ls] += tag[o];
large[rs] += tag[o];
tag[o] = ;
}
return;
} inline void add(int L, int R, int v, int l, int r, int o) {
if(L <= l && r <= R) {
tag[o] += v;
sum[o] += v * (r - l + );
large[o] += v;
return;
}
pushdown(l, r, o);
int mid = (l + r) >> ;
if(L <= mid) {
add(L, R, v, l, mid, o << );
}
if(mid < R) {
add(L, R, v, mid + , r, o << | );
}
pushup(o);
return;
} int main() { int n, m;
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++) {
scanf("%d%d", &a[i].l, &a[i].r);
a[i].len = a[i].r - a[i].l;
X[i << ] = a[i].l;
X[(i << ) - ] = a[i].r;
}
std::sort(a + , a + n + );
std::sort(X + , X + (n << ) + );
int t = std::unique(X + , X + (n << ) + ) - X - ;
int j = , ans = INF;
for(int i = ; i <= n; i++) {
a[i].l = std::lower_bound(X + , X + t + , a[i].l) - X;
a[i].r = std::lower_bound(X + , X + t + , a[i].r) - X;
add(a[i].l, a[i].r, , , t, );
while(large[] >= m) {
add(a[j].l, a[j].r, -, , t, );
//printf("large[1] = %d ans = %d \n i = %d j = %d \n", large[1], ans, i, j);
ans = std::min(ans, a[i].len - a[j].len);
j++;
}
}
if(ans == INF) {
ans = -;
}
printf("%d\n", ans);
return ;
}

AC代码

这个sum其实是不必要的。

然后我还用动态开点写了一发......被卡空间了。

 #include <cstdio>
#include <algorithm> const int N = , INF = 0x3f3f3f3f; int large[N * ], tag[N * ], root, ls[N * ], rs[N * ], tot; struct ITV {
int r, l, len;
inline bool operator <(const ITV &w) const {
return len < w.len;
}
}a[N]; inline void pushup(int o) {
large[o] = std::max(large[ls[o]], large[rs[o]]);
return;
} inline void pushdown(int l, int r, int o) {
if(tag[o]) {
int mid = (l + r) >> ;
if(ls[o]) {
large[ls[o]] += tag[o];
tag[ls[o]] += tag[o];
}
if(rs[o]) {
large[rs[o]] += tag[o];
tag[rs[o]] += tag[o];
}
tag[o] = ;
}
return;
} inline void add(int L, int R, int v, int l, int r, int &o) {
if(!o) {
o = ++tot;
}
if(L <= l && r <= R) {
tag[o] += v;
large[o] += v;
return;
}
if(!ls[o]) {
ls[o] = ++tot;
}
if(!rs[o]) {
rs[o] = ++tot;
}
pushdown(l, r, o);
int mid = (l + r) >> ;
if(L <= mid) {
add(L, R, v, l, mid, ls[o]);
}
if(mid < R) {
add(L, R, v, mid + , r, rs[o]);
}
pushup(o);
return;
} int main() { int n, m, lm = ;
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++) {
scanf("%d%d", &a[i].l, &a[i].r);
a[i].len = a[i].r - a[i].l;
lm = std::max(lm, a[i].r);
}
std::sort(a + , a + n + );
int j = , ans = INF;
for(int i = ; i <= n; i++) {
add(a[i].l, a[i].r, , , lm, root);
while(large[] >= m) {
add(a[j].l, a[j].r, -, , lm, root);
//printf("large[1] = %d ans = %d \n i = %d j = %d \n", large[1], ans, i, j);
ans = std::min(ans, a[i].len - a[j].len);
j++;
}
}
if(ans == INF) {
ans = -;
}
printf("%d\n", ans);
return ;
}

95分动态开点

洛谷P1712 区间的更多相关文章

  1. 洛谷P1712 [NOI2016]区间 尺取法+线段树+离散化

    洛谷P1712 [NOI2016]区间 noi2016第一题(大概是签到题吧,可我还是不会) 链接在这里 题面可以看链接: 先看题意 这么大的l,r,先来个离散化 很容易,我们可以想到一个结论 假设一 ...

  2. [Noi2016]区间 BZOJ4653 洛谷P1712 Loj#2086

    额... 首先,看到这道题,第一想法就是二分答案+线段树... 兴高采烈的认为我一定能AC,之后发现n是500000... nlog^2=80%,亲测可过... 由于答案是求满足题意的最大长度-最小长 ...

  3. 【洛谷 P1712】 [NOI2016]区间 (线段树+尺取)

    题目链接 emmm看起来好像无从下手, \(l_i,r_i\)这么大,肯定是要离散化的. 然后我们是选\(m\)个区间,我们先对这些区间按长度排个序也不影响. 排序后,设我们取的\(m\)个区间的编号 ...

  4. 洛谷 P1712 [NOI2016]区间(线段树)

    传送门 考虑将所有的区间按长度排序 考虑怎么判断点被多少区间覆盖,这个可以离散化之后用一棵权值线段树来搞 然后维护两个指针$l,r$,当被覆盖次数最多的点的覆盖次数小于$m$时不断右移$r$,在覆盖次 ...

  5. [洛谷P1712] NOI2016 区间

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

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

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

  7. 洛谷——P2082 区间覆盖(加强版)

    P2082 区间覆盖(加强版) 题目描述 已知有N个区间,每个区间的范围是[si,ti],请求出区间覆盖后的总长. 输入输出格式 输入格式: N s1 t1 s2 t2 …… sn tn 输出格式: ...

  8. 洛谷P2082 区间覆盖(加强版)(珂朵莉树)

    传送门 虽然是黄题而且还是一波离散就能解决的东西 然而珂朵莉树还是很好用 相当于一开始区间全为0,然后每一次区间赋值,问最后总权值 珂朵莉树搞一搞就好了 //minamoto #include< ...

  9. 洛谷1063 +区间dp(经典问题)

    题目网址:https://www.luogu.com.cn/problem/P1063 题意大致是:给定一个序列An,第i个元组表示为(Ai,Ai+1),序列位置不变,当合并一个区间[l,l+1]时开 ...

随机推荐

  1. Java8 Stream实例--统计出所有含‘张’字的人员的平均年龄

    package com.zhangxueliang.demo; import java.util.ArrayList; import java.util.List; import java.util. ...

  2. vue图片被加了盗链

    https://www.cnblogs.com/dongcanliang/archive/2017/04/01/6655061.html <meta name="referrer&qu ...

  3. mysql数据库修改数据表引擎的方法

    对于MySQL数据库,如果你要使用事务以及行级锁就必须使用INNODB引擎.如果你要使用全文索引,那必须使用myisam. INNODB的实用性,安全性,稳定性更高但是效率比MYISAM稍差,但是有的 ...

  4. python之路--模块和包

    一 . 模块 ⾸先,我们先看⼀个老⽣常谈的问题. 什么是模块. 模块就是⼀个包含了python定义和声明的⽂件, ⽂件名就是模块的名字加上.py后缀. 换句话说我们⽬前写的所有的py⽂件都可以看成是⼀ ...

  5. linux audit审计(8)--开启audit对系统性能的影响

    我们使用测试性能的工具,unixbench,它有一下几项测试项目: Execl Throughput 每秒钟执行 execl 系统调用的次数 Pipe Throughput 一秒钟内一个进程向一个管道 ...

  6. mac 电脑 打开隐藏文件

    command +shift +. 第一次是打开,第二次是关闭

  7. 使用JAVA获取JSON报文

    基本JSON格式: { "name": "liming", "age": "13", "array" ...

  8. Memcached cas 陷阱

    本地使用的 php7环境,测试好上传到服务器后发现memcached get 报错,服务器上是php5环境: 出错代码如下: $memConnect->get($key,null, Memcac ...

  9. C#,单元测试

    C#,单元测试入门(以下内容可能来自网络) 一.什么叫单元测试(unit testing)? 是指对软件中的最小可测试单元进行检查和验证.对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体 ...

  10. Nginx 减少磁盘读写次数

    L:133