题目大意

  数轴上有\(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. Vladik and Complicated Book CodeForces - 811B (思维实现)

    Vladik had started reading a complicated book about algorithms containing n pages. To improve unders ...

  2. 砝码组合(dfs)

    砝码组合  题目内容:用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量.如果只有5个砝码,重量分别是1,3,9,27,81.则它们可以组合称出1到121之间任意整数重量(砝码允许放在左右两 ...

  3. Jeecg-Boot Spring Boot

    Jeecg-Boot 1.0 发布,企业级快速开发平台 - 开源中国https://www.oschina.net/news/104889/jeecg-boot-1-0-released

  4. SpringMVC controller 时间 T

    Spring MVC 之 处理Date类型 - carl.zhao的专栏 - CSDN博客https://blog.csdn.net/u012410733/article/details/727730 ...

  5. Mysql连接数、线程数、数据包

    https://blog.csdn.net/qq_26545305/article/details/79675507

  6. 使用css控制文字显示几行并且剩余部分隐藏(移动端和PC端同样适用)

    前言 有些需求需要我们控制一段文本最多显示几行,就像逛淘宝京东的评价楼层一样,有时可能还需要隐藏剩余部分,这样的需求我们怎么来解决呢? 解决办法 我们完全可以使用css来解决这一需求 1. 解决文本显 ...

  7. 使用docker化的nginx 反向代理 docker化的GSCloud 的方法

    1. 首先将nginx 的image pull 下来. docker pull nginx 2. 将最近的可用的 参数文件 复制过来当一个目录 mkdir /nginx ssh root@linuxs ...

  8. Select2 4.0.5 API

    详细属性参考官方API,https://github.com/select2/select2/releases/tag/4.0.5 注:4.0.5版本API与3.x版本有差异,有些属性已废弃,以下列出 ...

  9. Decoder is not a @Sharable handler, so can't be added or removed multiple times

    Decoder is not a @Sharable handler, so can't be added or removed multiple times final MyMessageDecod ...

  10. centos安装Tesseract

    yum安装(推荐) yum search tesseract yum install tesseract.x86_64 -y pip3 install pytesseract pip3 install ...