博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NOI2016 区间 【线段树】
阅读量:4604 次
发布时间:2019-06-09

本文共 2852 字,大约阅读时间需要 9 分钟。

题目

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

对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。区间 [li,ri] 的长度定义为 ri−li,即等于它的右端点的值减去左端点的值。
求所有合法方案中最小的花费。如果不存在合法的方案,输出 −1。

输入格式

第一行包含两个正整数 n,m用空格隔开,意义如上文所述。保证 1≤m≤n

接下来 n行,每行表示一个区间,包含用空格隔开的两个整数 li 和 ri 为该区间的左右端点。
N<=500000,M<=200000,0≤li≤ri≤10^9

输出格式

只有一行,包含一个正整数,即最小花费。

输入样例

6 3

3 5

1 2

3 4

2 2

1 5

1 4

输出样例

2

题解

比较容易想到,如果我们对所选的区间都+1,那么一定存在某个位置的值>=m

先对区间离散化
这样我们可以得到一个\(O(n^3)\)的算法

区间修改求最值,离散化后用线段树优化,可以做到\(O(n^2logn)\)

为了进一步减小一个n,我们将区间按区间长度排序

从小开始逐个加入线段树中,直到出现>=m的位置,再尝试从小开始从线段树中删除,直至满足>=m时再移动右端点

可以证明这样做的正确性

因为区间过多不影响存在某位置>=m,通过不断移动右端点,有解一定可以判出
设当前解为len,如果不移动左端点,右端点移动的结果一定不会比len要小
所以在满足条件的情况下应尽量移动左端点
\(O(nlogn)\)

#include
#include
#include
#include
#include
#define LL long long int#define REP(i,n) for (int i = 1; i <= (n); i++)#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<
<<' '; puts("");#define ls (u << 1)#define rs (u << 1 | 1)using namespace std;const int maxn = 1000005,maxm = 500005,INF = 1000000000;inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();} while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();} return out * flag;}struct node{int l,r;}e[maxm];int b[maxn],bi,tot = 1,n,m,ans = INF;int mx[4 * maxn],tag[4 * maxn];inline bool operator <(const node& a,const node& x){ return (b[a.r] - b[a.l]) < (b[x.r] - b[x.l]);}int getn(int x){return lower_bound(b + 1,b + 1 + tot,x) - b;}void pd(int u){ if (tag[u]){ mx[ls] += tag[u]; mx[rs] += tag[u]; tag[ls] += tag[u]; tag[rs] += tag[u]; tag[u] = 0; }}void modify(int u,int l,int r,int L,int R,int x){ if (l >= L && r <= R){ mx[u] += x; tag[u] += x; return; } pd(u); int mid = l + r >> 1; if (mid >= L) modify(ls,l,mid,L,R,x); if (mid < R) modify(rs,mid + 1,r,L,R,x); mx[u] = max(mx[ls],mx[rs]);}int main(){ n = read(); m = read(); for (int i = 1; i <= n; i++) b[++bi] = e[i].l = read(),b[++bi] = e[i].r = read(); sort(b + 1,b + 1 + bi); for (int i = 2; i <= bi; i++) if (b[i] != b[tot]) b[++tot] = b[i]; for (int i = 1; i <= n; i++) e[i].l = getn(e[i].l),e[i].r = getn(e[i].r); sort(e + 1,e + 1 + n); modify(1,1,tot,e[1].l,e[1].r,1); int l = 1,r = 1,L,R; L = R = b[e[1].r] - b[e[1].l]; if (mx[1] >= m) ans = min(ans,R - L); while (r <= n){ while (mx[1] >= m && l < r){ modify(1,1,tot,e[l].l,e[l].r,-1); l++; L = b[e[l].r] - b[e[l].l]; if (mx[1] >= m) ans = min(ans,R - L); } r++; if (r > n) break; R = b[e[r].r] - b[e[r].l]; modify(1,1,tot,e[r].l,e[r].r,1); if (mx[1] >= m) ans = min(ans,R - L); } printf("%d\n",ans == INF ? -1 : ans); return 0;}

转载于:https://www.cnblogs.com/Mychael/p/8465241.html

你可能感兴趣的文章
[luogu4310] 绝世好题 (递推)
查看>>
[luogu3203 HNOI2010] 弹飞绵羊 (分块)
查看>>
-Dmaven.multiModuleProjectDirectory system propery is not set.
查看>>
Python2 unichr() 函数
查看>>
Python 字典 copy()方法
查看>>
Minimum Path Sum
查看>>
Remove Duplicates from Sorted Array II
查看>>
常量指针和指针常量巧妙记忆方法[转]
查看>>
python-haproxy作业讲解视频总结
查看>>
mui搜索框 搜索点击事件
查看>>
select2 下拉搜索控件
查看>>
WebAPI常见的鉴权方法,及其适用范围
查看>>
08. 删除重复&海量数据
查看>>
重新想象 Windows 8 Store Apps (71) - 其它: C# 调用 C++
查看>>
发布mvc遇到的HTTP错误 403.14-Forbidden解决办法
查看>>
记录一些好用的工具
查看>>
超链接样式设置(去下划线)(转)
查看>>
2016012003+陈琦+散列函数的应用及其安全性
查看>>
Android 状态栏通知Notification、NotificationManager详解
查看>>
UIApplicationDelegate协议
查看>>