洛谷 P4198 楼房重建 线段树维护单调栈
P4198 楼房重建
题目链接
https://www.luogu.org/problemnew/show/P4198
题目描述
小A的楼房外有一大片施工工地,工地上有N栋待建的楼房。每天,这片工地上的房子拆了又建、建了又拆。他经常无聊地看着窗外发呆,数自己能够看到多少栋房子。
为了简化问题,我们考虑这些事件发生在一个二维平面上。小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和(i,Hi)的线段表示,其中Hi为第i栋楼房的高度。如果这栋楼房上任何一个高度大于0的点与(0,0)的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的。
施工队的建造总共进行了M天。初始时,所有楼房都还没有开始建造,它们的高度均为0。在第i天,建筑队将会将横坐标为Xi的房屋的高度变为Yi(高度可以比原来大—修建,也可以比原来小—拆除,甚至可以保持不变—建筑队这天什么事也没做)。请你帮小A数数每天在建筑队完工之后,他能看到多少栋楼房?
输入输出格式
输入格式:
第一行两个正整数N,M
接下来M行,每行两个正整数Xi,Yi
输出格式:
M行,第i行一个整数表示第i天过后小A能看到的楼房有多少栋
输入输出样例
输入样例#1:
3 4
2 4
3 6
1 1000000000
1 1
输出样例#1:
1
1
1
2
说明
对于所有的数据\(1<=Xi<=N,1<=Yi<=10^9\)
\(N,M<=100000\)
题解
线段树维护,记录一个max,sum即可,代码很短,但是有个点需要注意,我在代码相应位置标记了。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 100050
int n,m;
struct Tree{int l,r,sum; double max;}tr[N<<2];
template<typename T>void read(T&x)
{
ll k=0; char c=getchar();
x=0;
while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
if (c==EOF)exit(0);
while(isdigit(c))x=x*10+c-'0',c=getchar();
x=k?-x:x;
}
void read_char(char &c)
{while(!isalpha(c=getchar())&&c!=EOF);}
int get_sum(int x,double tt)
{
if (tr[x].max<=tt)return 0;
if (tr[x].l==tr[x].r)return tr[x].sum;
Tree &a=tr[x<<1],&b=tr[x<<1|1];
if (tt>=a.max)return get_sum(x<<1|1,tt);
else return get_sum(x<<1,tt)+tr[x].sum-a.sum;//这里不能写成 get_sum(x<<1,tt)+b.sum;
}
void push_up(int x)
{
Tree &a=tr[x<<1],&b=tr[x<<1|1];
tr[x].max=max(a.max,b.max);
tr[x].sum=a.sum+get_sum(x<<1|1,a.max);
}
void bt(int x,int l,int r)
{
tr[x].l=l; tr[x].r=r;
if (l==r)return;
int mid=(l+r)>>1;
bt(x<<1,l,mid);
bt(x<<1|1,mid+1,r);
}
void update(int x,int p,double tt)
{
if (tr[x].l==tr[x].r)
{
tr[x].max=tt;
tr[x].sum=1;
return;
}
int mid=(tr[x].l+tr[x].r)>>1;
if (p<=mid)update(x<<1,p,tt);
else update(x<<1|1,p,tt);
push_up(x);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("aa.in","r",stdin);
#endif
read(n); read(m);
bt(1,1,n);
for(int i=1;i<=m;i++)
{
int x;double tt;
read(x); read(tt);tt=tt/x;
update(1,x,tt);
printf("%d\n",tr[1].sum);
}
}
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 100050
int n,m;
struct Tree{int l,r,sum; double max;}tr[N<<2];
template<typename T>void read(T&x)
{
ll k=0; char c=getchar();
x=0;
while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
if (c==EOF)exit(0);
while(isdigit(c))x=x*10+c-'0',c=getchar();
x=k?-x:x;
}
void read_char(char &c)
{while(!isalpha(c=getchar())&&c!=EOF);}
int get_sum(int x,double tt)
{
if (tr[x].max<=tt)return 0;
if (tr[x].l==tr[x].r)return tr[x].sum;
Tree &a=tr[x<<1],&b=tr[x<<1|1];
if (tt>=a.max)return get_sum(x<<1|1,tt);
else return get_sum(x<<1,tt)+tr[x].sum-a.sum;//这里不能写成 get_sum(x<<1,tt)+b.sum;
}
void push_up(int x)
{
Tree &a=tr[x<<1],&b=tr[x<<1|1];
tr[x].max=max(a.max,b.max);
tr[x].sum=a.sum+get_sum(x<<1|1,a.max);
}
void bt(int x,int l,int r)
{
tr[x].l=l; tr[x].r=r;
if (l==r)return;
int mid=(l+r)>>1;
bt(x<<1,l,mid);
bt(x<<1|1,mid+1,r);
}
void update(int x,int p,double tt)
{
if (tr[x].l==tr[x].r)
{
tr[x].max=tt;
tr[x].sum=1;
return;
}
int mid=(tr[x].l+tr[x].r)>>1;
if (p<=mid)update(x<<1,p,tt);
else update(x<<1|1,p,tt);
push_up(x);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("aa.in","r",stdin);
#endif
read(n); read(m);
bt(1,1,n);
for(int i=1;i<=m;i++)
{
int x;double tt;
read(x); read(tt);tt=tt/x;
update(1,x,tt);
printf("%d\n",tr[1].sum);
}
}
洛谷 P4198 楼房重建 线段树维护单调栈的更多相关文章
- 洛谷P4198 楼房重建(线段树)
题意 题目链接 Sol 别问我为什么发两遍 就是为了骗访问量 这个题的线段树做法,,妙的很 首先一个显然的结论:位置\(i\)能被看到当且仅当\(\frac{H_k}{k} < \frac{H_ ...
- 洛谷P4198 楼房重建 (分块)
洛谷P4198 楼房重建 题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题, ...
- [CSP-S模拟测试]:陶陶摘苹果(线段树维护单调栈)
题目传送门(内部题116) 输入格式 第一行两个整数$n,m$,如题 第二行有$n$个整数表示$h_1-h_n(1\leqslant h_i\leqslant 10^9)$ 接下来有$m$行,每行两个 ...
- [Luogu P4198]楼房重建(线段树)
题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些事件发生在一个 ...
- 洛谷 P4198 楼房重建
思路 此题可转化为以下模型 给定序列\(a[1...n]\),支持单点修改,每次求区间单调栈大小 \(n,Q\le 10^5\) 区间单调栈是什么呢?对于一个区间,建立一个栈,首先将第一个元素入栈,从 ...
- 洛谷P4198 楼房重建 单调栈+线段树
正解:单调栈+线段树 解题报告: 传送门! 首先考虑不修改的话就是个单调栈板子题昂,这个就是 然后这题的话,,,我怎么记得之前考试好像有次考到了类似的题目昂,,,?反正我总觉着这方法似曾相识的样子,, ...
- luogu P4198 楼房重建——线段树
题目大意: 小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和(i,Hi)的线段表示,其中Hi为第i栋楼房的高度.如果这栋楼房上任何一个高度大于0的点与(0,0)的连线没有与之前的线 ...
- [BZOJ 2957]楼房重建(THU2013集训)(线段树维护单调栈)
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2957 分析: 根据题意,就是比较斜率大小 只看一段区间的话,那么这段区间能看见的楼房数量就是这 ...
- 洛谷 P4198 楼房重建 题解
题面 首先你要知道题问的是什么:使用一种数据结构,动态地维护以1为起点地最长上升子序列(把楼房的高度转化成斜率地序列)的长度: 怎么做?线段树! 我们在线段树上维护两个东西:1.这个区间内斜率的最大值 ...
随机推荐
- 【概率论】1-2:计数方法(Counting Methods)
title: [概率论]1-2:计数方法(Counting Methods) categories: Mathematic Probability keywords: Counting Methods ...
- Scarily interesting! (URAL - 2021)
Problem This year at Monsters University it is decided to arrange Scare Games. At the Games all camp ...
- scrapy框架之log日志
scrapy中的debug信息 在scrapy中设置log 1.在settings中设置log级别,在settings.py中添加一行: Scrapy提供5层logging级别: CRITICAL - ...
- Git生成本机SSH Key并添加到GitHub中
1.检查电脑里是否有SSH Key 打开git Bash客户端 cd ~/.ssh ls 如果有就会输出下面内容 config id_rsa id_rsa.pub known_hosts 2.创建 邮 ...
- 异步机制 - APC
APC : An asynchronous procedure call,异步过程调用,是微软提供的一种在线程上下文中执行代码的机制.当向一个线程插入一个USER APC时,如果线程进入alertab ...
- 风控分类模型种类(决策、排序)比较与模型评估体系(ROC/gini/KS/lift)
python信用评分卡建模(附代码,博主录制) https://study.163.com/course/introduction.htm?courseId=1005214003&utm_ca ...
- Objective-C如何自己实现一个for-each语法形式
我们在用Objective-C编写程序时,很多时候会用到NSArray来作为线性列表来使用.我们在枚举这个数组所有元素的使用可以通过下列方法进行: for(id obj in anArray) { } ...
- C++ STL partial_sort_copy greater
#include <iostream>#include <deque>#include <algorithm>#include <vector>#inc ...
- C++ STL 逆转旋转 reverse reverse_copy rotate
#include <iostream>#include <algorithm>#include <vector>#include <iterator> ...
- pip使用笔记
例子: pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -U funcat -i: 指定库的安装源 -U:升级 原来已经安装的包,不带U ...