BZOJ4653 尺取法 + 线段树
https://www.lydsy.com/JudgeOnline/problem.php?id=4653
首先很容易想到离散之后排序,用线段树或者树状数组去维护。
问题在于按照什么排序,如果按照左端点右端点排序,线段树就需要维护最大值最小值和区间和等等信息,在区间和超过M之后最大值就变为了K大到最大的信息,不但麻烦而且难以下手。
所以想到直接按照区间长度排序,仅仅维护一个区间最值,代表这个区间里最大的点被覆盖了多少次,然后用一种尺取的思想,使得线段树里的最大值一值不超过M,如果超过了就在尾部开始删除直到M以下,与此同时更新最大值。
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = 5e5 + ;
const int maxm = 2e5 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
int Hash[maxn * ];
int len[maxn];
PII line[maxn];
struct Tree{
int l,r,lazy,Max;
}tree[maxn << ];
void Build(int t,int l,int r){
tree[t].l = l; tree[t].r = r;
tree[t].lazy = tree[t].Max = ;
if(l == r) return;
int m = (l + r) >> ;
Build(t << ,l,m); Build(t << | ,m + ,r);
}
void Pushdown(int t){
if(tree[t].lazy){
tree[t << ].lazy += tree[t].lazy;
tree[t << | ].lazy += tree[t].lazy;
tree[t << ].Max += tree[t].lazy;
tree[t << | ].Max += tree[t].lazy;
tree[t].lazy = ;
}
}
void Pushup(int t){
tree[t].Max = max(tree[t << ].Max,tree[t << | ].Max);
}
void update(int t,int l,int r,int w){
if(l <= tree[t].l && tree[t].r <= r){
tree[t].Max += w;
tree[t].lazy += w;
return;
}
Pushdown(t);
int m = (tree[t].l + tree[t].r) >> ;
if(r <= m) update(t << ,l,r,w);
else if(l > m) update(t << | ,l,r,w);
else{
update(t << ,l,m,w); update(t << | ,m + ,r,w);
}
Pushup(t);
}
bool cmp(PII a,PII b){
return a.se - a.fi < b.se - b.fi;
}
int main(){
Sca2(N,M);
int cnt = ;
for(int i = ; i <= N; i ++){
line[i].fi = read(); line[i].se = read();
Hash[++cnt] = line[i].fi; Hash[++cnt] = line[i].se;
}
sort(Hash + ,Hash + + cnt);
sort(line + ,line + + N,cmp);
cnt = unique(Hash + ,Hash + + cnt) - Hash - ;
for(int i = ; i <= N ; i ++){
len[i] = line[i].se - line[i].fi;
line[i].fi = lower_bound(Hash + ,Hash + + cnt,line[i].fi) - Hash;
line[i].se = lower_bound(Hash + ,Hash + + cnt,line[i].se) - Hash;
}
Build(,,cnt);
int tail = ;
int ans = INF;
for(int i = ; i <= N ; i ++){
update(,line[i].fi,line[i].se,);
while(tree[].Max >= M){
ans = min(ans,len[i] - len[tail]);
update(,line[tail].fi,line[tail].se,-);
tail++;
}
}
if(ans == INF) ans = -;
Pri(ans);
return ;
}
BZOJ4653 尺取法 + 线段树的更多相关文章
- luogu1712 区间 (尺取法+线段树)
先把区间按照长度从小到大排序,然后用尺取法来做 大概就是先一点一点把区间算上 直到某个点被覆盖了m次,然后一点一点把最前面的区间扔掉,直到没有点被覆盖m次,这样反复做(相当于是它选择的区间左右端点在那 ...
- codeforces 652C C. Foe Pairs(尺取法+线段树查询一个区间覆盖线段)
题目链接: C. Foe Pairs time limit per test 1 second memory limit per test 256 megabytes input standard i ...
- luogu P1712 [NOI2016]区间 贪心 尺取法 线段树 二分
LINK:区间 没想到尺取法. 先说暴力 可以发现答案一定可以转换到端点处 所以在每个端点从小到大扫描线段就能得到答案 复杂度\(n\cdot m\) 再说我的做法 想到了二分 可以进行二分答案 从左 ...
- 洛谷P1712 [NOI2016]区间 尺取法+线段树+离散化
洛谷P1712 [NOI2016]区间 noi2016第一题(大概是签到题吧,可我还是不会) 链接在这里 题面可以看链接: 先看题意 这么大的l,r,先来个离散化 很容易,我们可以想到一个结论 假设一 ...
- BZOJ4653 [NOI2016]区间 [线段树,离散化]
题目传送门 区间 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就 ...
- 【BZOJ-4653】区间 线段树 + 排序 + 离散化
4653: [Noi2016]区间 Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 107 Solved: 70[Submit][Status][Di ...
- BZOJ4653: [Noi2016]区间(线段树 双指针)
题意 题目链接 Sol 按照dls的说法,一般这一类的题有两种思路,一种是枚举一个点\(M\),然后check它能否成为答案.但是对于此题来说好像不好搞 另一种思路是枚举最小的区间长度是多少,这样我们 ...
- BZOJ4653:[NOI2016]区间(线段树)
Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x ...
- 2018.08.17 bzoj4653: [Noi2016]区间(线段树+尺取法)
传送门 将坐标离散化之后直接用尺取法(双指针)+线段树维护. 其实就是说只要目前所有点的被覆盖次数是大于等于m的就移动左指针删除区间更新答案,否则移动右指针加入区间更新答案. 话说忘记排序以及建树的时 ...
随机推荐
- UVA 690 Pipeline Scheduling
https://vjudge.net/problem/UVA-690 题目 你有一台包含5个工作单元的计算机,还有10个完全相同的程序需要执行.每个程序需要$n(n<20)$个时间片来执行,可以 ...
- xshell使用rz/sz完成文件上传下载
yum -y install lrzsz 安装lrzsz 使用rz完成文件上传 使用sz完成文件下载
- LVS负载均衡群集
概述 群集的类型:无论是哪种服务器,都至少包括两台节点服务器,而对外表现为一个整体,只提供一个访问入口(域名或IP地址),相当于一台大型计算机.根据群集所针对的目标差异,可以分为以下三个类型: 1.负 ...
- 微信小程序——部署云函数【三】
部署login云函数 不部署的话,点击获取openid会报错,报错如下 解决方案呢,很明显的已经告诉我们了 搭建云环境 开通 同意协议 新建环境 每个小程序账号可以创建两个免费环境 确定 部署后再次请 ...
- ☆ [POJ1021] Intervals 「差分约束」
传送门 >Here< 题意:给出N段区间,并告诉你每段区间里有几个数(一个位置只能放一个数) 问总共至少有几个数 解题思路 差分约束题,本蒟蒻也是第一次做差分约束题…… 所谓差分约束,常常 ...
- 【CTSC2017】【BZOJ4903】吉夫特 卢卡斯定理 DP
题目描述 给你一个长度为\(n\)的数列\(a\),求有多少个长度\(\geq 2\)的不上升子序列\(a_{b_1},a_{b_2},\ldots,a_{b_k}\)满足 \[ \prod_{i=2 ...
- IDEA如何查看maven的依赖结构
打开方式: 方法一:该工具有个Maven Projects窗口,一般在右侧能够找到,如果没有可以从菜单栏打开:View>Tool Windows>Maven Projects:选择要分析的 ...
- Ionic生命周期与注意点
需要注意的地方是:在走页面的生命周期以前,会先走构造方法 构造方法只走一次,除非再次创建这个页面.所以如果先push了一个新页面,然后再调用pop()返回到之前的页面,那么是不会走构造方法里面的方法的 ...
- Java 枚举(enum) 详解7种常见的用法
Java 枚举(enum) 详解7种常见的用法 来源 https://blog.csdn.net/qq_27093465/article/details/52180865 JDK1.5引入了新的类型— ...
- emwin之自绘制 BUTTON 图形的一些问题
@2018-11-8 [小记] [需求] 官方只提供圆角矩形图形,其他图形及颜色需求则要自己实现 [注意] 通过回调函数自实现的图形绘制存在该回调函数一直被调用的现象,而非像窗口回调函数中 BUTTO ...