题目大意

  数轴上有\(n\)个闭区间\([l_1,r_1],[l_2,r_2],\ldots,[l_n,r_n]\),你要选出\(m\)个区间,使得存在一个\(x\),对于每个选出的区间\([l_i,r_i]\)都有\(x\in[l_i,r_i]\)。

  一个方案的代价是最长区间长度减去最短区间长度。

  求最小的代价。

  无解输出\(-1\)。

  \(m\leq n\leq 500000\)

题解

  就是选出\(m\)个区间,包含同一个点。

  如果多选一些区间,那么答案不会变小。

  问题转化成选一些区间,使得存在一个点被\(m\)个区间包含。

  把这些区间按长度排序,用线段树维护每个点被包含的次数。

  枚举左端点和右端点,查询是否有一个点被包含\(m\)次。

  设\(f_i\)为选第\(i\)个区间为最长的区间时最短的区间是哪个。

  显然\(f_i\)是单调递增的

  直接用两个指针维护就行了

  因为区间端点的范围很大,所以要离散化。

  时间复杂度:\(O(n\log n)\)

题解

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
#include<functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
if(a>b)
swap(a,b);
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
int rd()
{
int s=0,c;
while((c=getchar())<'0'||c>'9');
do
{
s=s*10+c-'0';
}
while((c=getchar())>='0'&&c<='9');
return s;
}
int upmin(int &a,int b)
{
if(b<a)
{
a=b;
return 1;
}
return 0;
}
int upmax(int &a,int b)
{
if(b>a)
{
a=b;
return 1;
}
return 0;
}
struct section
{
int l,r;
int d;
};
int cmp(section a,section b)
{
return a.d<b.d;
}
namespace seg
{
struct node
{
int l,r,ls,rs,s,t;
};
node a[2000010];
int n;
void build(int &p,int l,int r)
{
p=++n;
a[p].l=l;
a[p].r=r;
if(l==r)
return;
int mid=(l+r)>>1;
build(a[p].ls,l,mid);
build(a[p].rs,mid+1,r);
}
void add(int p,int v)
{
a[p].s+=v;
a[p].t+=v;
}
void push(int p)
{
if(a[p].l!=a[p].r&&a[p].t)
{
add(a[p].ls,a[p].t);
add(a[p].rs,a[p].t);
a[p].t=0;
}
}
void add(int p,int l,int r,int v)
{
if(l<=a[p].l&&r>=a[p].r)
{
add(p,v);
return;
}
int mid=(a[p].l+a[p].r)>>1;
push(p);
if(l<=mid)
add(a[p].ls,l,r,v);
if(r>mid)
add(a[p].rs,l,r,v);
a[p].s=max(a[a[p].ls].s,a[a[p].rs].s);
}
int query(int p,int l,int r)
{
if(l>r)
return 0;
if(l<=a[p].l&&r>=a[p].r)
return a[p].s;
push(p);
int mid=(a[p].l+a[p].r)>>1;
int res=0;
if(l<=mid)
upmax(res,query(a[p].ls,l,r));
if(r>mid)
upmax(res,query(a[p].rs,l,r));
return res;
}
}
using seg::build;
using seg::add;
using seg::query;
section a[500010];
int d[1000010];
int main()
{
// open("bzoj4653");
int n,m;
scanf("%d%d",&n,&m);
int i;
int t=0;
for(i=1;i<=n;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
a[i].d=a[i].r-a[i].l+1;
d[++t]=a[i].l;
d[++t]=a[i].r;
}
sort(d+1,d+t+1);
t=unique(d+1,d+t+1)-d-1;
sort(a+1,a+n+1,cmp);
for(i=1;i<=n;i++)
{
a[i].l=lower_bound(d+1,d+t+1,a[i].l)-d;
a[i].r=lower_bound(d+1,d+t+1,a[i].r)-d;
}
int j=1;
int rt;
build(rt,1,t);
int ans=0x7fffffff;
for(i=1;i<=n;i++)
{
add(rt,a[i].l,a[i].r,1);
while(max(query(rt,a[j].l,a[j].r)-1,max(query(rt,1,a[j].l-1),query(rt,a[j].r+1,t)))>=m)
{
add(rt,a[j].l,a[j].r,-1);
j++;
}
if(query(rt,1,t)>=m)
ans=min(ans,a[i].d-a[j].d);
}
if(ans==0x7fffffff)
ans=-1;
printf("%d\n",ans);
return 0;
}

【BZOJ4653】【NOI2016】区间 线段树的更多相关文章

  1. BZOJ4653 [NOI2016]区间 [线段树,离散化]

    题目传送门 区间 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就 ...

  2. BZOJ4653: [Noi2016]区间(线段树 双指针)

    题意 题目链接 Sol 按照dls的说法,一般这一类的题有两种思路,一种是枚举一个点\(M\),然后check它能否成为答案.但是对于此题来说好像不好搞 另一种思路是枚举最小的区间长度是多少,这样我们 ...

  3. BZOJ4653:[NOI2016]区间(线段树)

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

  4. 【BZOJ-4653】区间 线段树 + 排序 + 离散化

    4653: [Noi2016]区间 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 107  Solved: 70[Submit][Status][Di ...

  5. BZOJ.4653.[NOI2016]区间(线段树)

    BZOJ4653 UOJ222 考虑二分.那么我们可以按区间长度从小到大枚举每个区间,对每个区间可以得到一个可用区间长度范围. 我们要求是否存在一个点被这些区间覆盖至少\(m\)次.这可以用线段树区间 ...

  6. [NOI2016]区间 线段树

    [NOI2016]区间 LG传送门 考虑到这题的代价是最长边减最短边,可以先把边按长度排个序,双指针维护一个尺取的过程,如果存在包含某个点的区间数\(\ge m\),就更新答案并把左指针右移,这样做的 ...

  7. Luogu P1712 [NOI2016]区间(线段树)

    P1712 [NOI2016]区间 题意 题目描述 在数轴上有 \(N\) 个闭区间 \([l_1,r_1],[l_2,r_2],...,[l_n,r_n]\) .现在要从中选出 \(M\) 个区间, ...

  8. UOJ222 NOI2016 区间 线段树+FIFO队列

    首先将区间按长度排序后离散化端点(这里的“长度”指的是离散化之前区间的实际长度) 然后模拟一个队列,区间按排好的顺序依次进入,直到某个点被覆盖了M次.之后依次出队,直到所有点都被覆盖小于M次 修改和询 ...

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

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

  10. hdu 1540 Tunnel Warfare (区间线段树(模板))

    http://acm.hdu.edu.cn/showproblem.php?pid=1540 Tunnel Warfare Time Limit: 4000/2000 MS (Java/Others) ...

随机推荐

  1. 七、xadmin 编辑界面实现二级联动

    很多时候,我们会遇到这种需求,通过一个select框中选择的值,去动态的加载另一个下拉框中的内容 对于前端的同学来讲,这个本应该是一个很简单的需求,获取第一个下拉框的值然后通过ajax去动态加载即可. ...

  2. 使用 Emmet 生成 HTML 的语法详解

    生成 HTML 文档初始结构 HTML 文档的初始结构,就是包括 doctype.html.head.body 以及 meta 等内容.你只需要输入一个 “!” 就可以生成一个 HTML5 的标准文档 ...

  3. HDU - 1255 扫描线+离散化进阶

    这道题最开始我以为和HDU - 1542 那道题一样,只需要把cover次数改成2次即可,但是后面仔细一想,我们需要求的是覆盖次数大于等于2次的,这样的话,我们需要维护两个长度,HDU-1542 由于 ...

  4. matplotlib 入门之Sample plots in Matplotlib

    文章目录 Line Plot One figure, a set of subplots Image 展示图片 展示二元正态分布 A sample image Interpolating images ...

  5. c++入门之const初步理解

    关于const,首先建立这样的一个认识:const并不是定义了一个常量,而是定义了在某种环境下只读的变量.下面我们来区分一些东西: ; const int*p = &num; *p = ; i ...

  6. javascript与php与python的函数写法区别与联系

    1.javascript函数写法种类: (一).第一种 function test(param){ return 111; } (二).第二种 var test = function(param){ ...

  7. ImageProcessor组件

    ImageProcessor组件 开源免费的.NET图像即时处理的组件ImageProcessor   承接以前的组件系列,这个组件系列旨在介绍.NET相关的组件,让大家可以在项目中有一个更好的选择, ...

  8. Python_内置函数之round的幺蛾子

    pycharm运行结果 1 ret = round(0.5) print(ret) >>> 0 ret1 = round(1.5) print(ret1) >>> ...

  9. rest-framework解析器,url控制,分页,响应器,渲染器,版本控制

    解析器 1.json解析器 发一个json格式的post请求.后台打印: request_data---> {'title': '北京折叠'} request.POST---> <Q ...

  10. jmeter的jtl日志转html报告常见报错笔记

    问题:生成的jmeter文件可以放任意位置 输入命令转换hmtl报告 PS D:\user\80003288\桌面\Ques> jmeter -g .\test1.jtl -e -o .\rep ...