【BZOJ4653】【NOI2016】区间 线段树
题目大意
数轴上有\(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】区间 线段树的更多相关文章
- BZOJ4653 [NOI2016]区间 [线段树,离散化]
题目传送门 区间 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就 ...
- BZOJ4653: [Noi2016]区间(线段树 双指针)
题意 题目链接 Sol 按照dls的说法,一般这一类的题有两种思路,一种是枚举一个点\(M\),然后check它能否成为答案.但是对于此题来说好像不好搞 另一种思路是枚举最小的区间长度是多少,这样我们 ...
- BZOJ4653:[NOI2016]区间(线段树)
Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x ...
- 【BZOJ-4653】区间 线段树 + 排序 + 离散化
4653: [Noi2016]区间 Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 107 Solved: 70[Submit][Status][Di ...
- BZOJ.4653.[NOI2016]区间(线段树)
BZOJ4653 UOJ222 考虑二分.那么我们可以按区间长度从小到大枚举每个区间,对每个区间可以得到一个可用区间长度范围. 我们要求是否存在一个点被这些区间覆盖至少\(m\)次.这可以用线段树区间 ...
- [NOI2016]区间 线段树
[NOI2016]区间 LG传送门 考虑到这题的代价是最长边减最短边,可以先把边按长度排个序,双指针维护一个尺取的过程,如果存在包含某个点的区间数\(\ge m\),就更新答案并把左指针右移,这样做的 ...
- Luogu P1712 [NOI2016]区间(线段树)
P1712 [NOI2016]区间 题意 题目描述 在数轴上有 \(N\) 个闭区间 \([l_1,r_1],[l_2,r_2],...,[l_n,r_n]\) .现在要从中选出 \(M\) 个区间, ...
- UOJ222 NOI2016 区间 线段树+FIFO队列
首先将区间按长度排序后离散化端点(这里的“长度”指的是离散化之前区间的实际长度) 然后模拟一个队列,区间按排好的顺序依次进入,直到某个点被覆盖了M次.之后依次出队,直到所有点都被覆盖小于M次 修改和询 ...
- 洛谷$P1712\ [NOI2016]$区间 线段树
正解:线段树 解题报告: 传送门$QwQ$ $umm$很久以前做的了来补个题解$QwQ$ 考虑给每个区间按权值($r-l$从大往小排序,依次加入,然后考虑如果有一个位置被覆盖次数等于$m$了就可以把权 ...
- hdu 1540 Tunnel Warfare (区间线段树(模板))
http://acm.hdu.edu.cn/showproblem.php?pid=1540 Tunnel Warfare Time Limit: 4000/2000 MS (Java/Others) ...
随机推荐
- UVA 10791 -唯一分解定理的应用
#include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> ...
- Python—闭包
闭包的定义:即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数).而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量.参数.当其中一个这样的内部函数在包含它们的外部函数之外被调用时 ...
- PS调出唯美冷色情侣婚纱写真照
一.打开PS原片,原片是一张JPG格式的片子 色温较高整个画面较红离对着上面的我们标准的韩式色调我们来进行调节吧 ,我就不打太多文字解释一些基本常规了 二.韩式婚纱内景喜欢加点烟雾.其实我本人是不太喜 ...
- django之全局默认设置查看及admin语言设置
django之admin语言设置 admin后台管理默认使用的是英文,有时我们需要将其设置成自己的语言以方便使用管理: 将 LANGUAGE_CODE = '' 设置为欲设置的语言即可. 以下为dja ...
- 使用ajax请求后端程序时,关于目标程序路径问题
这里涉及到和PHP中类似的问题,有待更新!!!
- 简述nginx(1)
Nginx能做什么 1.反向代理 2.负载均衡 3.HTTP服务器(包含动静分离) 4.正向代理 反向代理 反向代理应该是Nginx做的最多的一件事了,什么是反向代理呢,以下是百度百科的说法:反向代理 ...
- python文件封装成*.exe文件(单文件和多文件)
环境:win10 64位 python3.7 单*.py文件打包Python GUI:程序打包为exe 一.安装Pyinstaller,命令pip install Pyinstaller,(大写的P ...
- Velocity ${} 和$!{}、!${}区别
前言 在使用Velocity时经常会看到三种使用变量的情况 情况一:${name} 情况二:$!{name} 情况三:!${name} 那么三者之间到底有什么区别呢?莫慌!!!哈哈 情况一:${nam ...
- Swagger2常用注解及其说明 (转)
Api 用在Controller中,标记一个Controller作为swagger的文档资源 属性名称 说明 value Controller的注解 description 对api资源的描述 hid ...
- ssh 登陆服务器原理
这里分两种情况,这两种情况都涉及到公钥加密的概念. 由于公钥加密概念作为基础就不在本文进行讨论了. 使用ssh对远程服务器进行密码登录发生了什么: 客户端通过ssh连接服务器 1. 首先服务器把自己的 ...