题意:给你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. Oracle 备份表数据

    --备份表数据 select * from t_owners; --创建备份表 create table t_owners_copy ( id number, name ), addressid nu ...

  2. 【学亮IT手记】jQuery text()/html()回调函数实例

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script sr ...

  3. js获取数组中相同元素数量

    <script> var array = new Array(1,2,5,1,4,4,2,3,5,1,1,5,5,5,6,7,3,9,9,10); var arr = new Array( ...

  4. Flutter之Container详解

    1 基本内容1.1 继续关系Object > Diagnosticable > DiagnosticableTree > Widget > StatelessWidget &g ...

  5. 转《在浏览器中使用tensorflow.js进行人脸识别的JavaScript API》

    作者 | Vincent Mühle 编译 | 姗姗 出品 | 人工智能头条(公众号ID:AI_Thinker) [导读]随着深度学习方法的应用,浏览器调用人脸识别技术已经得到了更广泛的应用与提升.在 ...

  6. centos7系统管理和运维实战——运维必备的网络管理技能(1)

    运维必备的网络管理技能 一.网络管理协议: 1.简单的两个概念:    DHCP(动态主机配置协议):如果网络结构要更改,需要从新初始化网络参数,手机用动态主机配置协议可以避免这个问题.客户端可以从D ...

  7. Javaweb小结之——JavaBean+持久层

    数据持久层学习了JDBC.连接池以及DBUtil 思考一下,在学会使用SSM框架之前,还是先多使用DBUtil吧 数据库持久层的JDBC.连接池和DBUtil,这个链接给我了一些参考https://b ...

  8. npm安裝、卸載、刪除、撤銷發佈包、更新版本信息

    利用npm安裝包: 全局安裝:npm install -g 模塊安裝 局部安裝(可以使用repuire(‘模塊名’)引用):npm install 模塊名稱 如果權限不夠,就是用管理員方式安裝. 本地 ...

  9. 洛谷 p1019 单词接龙

    题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合 ...

  10. Lodop提示安装或升级的注意事项

    LODOP的LodopFuncs.js文件里,自动判断浏览器类型提示下载哪个,根据版本号比较判断提示升级.此文章是以前写的,图示可能过旧,新版提示不同,但是LodopFuncs.js里各个方面变动不大 ...