BZOJ2957 楼房重建
Description
平面上有\(n\)个位置\(1\dots n\),第\(i\)个位置有一个高为\(H_i\)的楼房;所有\(H\)初始值为\(0\)。每次修改一个\(H_i\),求修改后从\((0,0)\)点可以看到多少楼房。\(n,m\leq10^5\)。
Solution
线段树。
首先可以发现某个楼房能够被看到当且仅当它的顶点斜率>所有前面的楼房顶点的斜率。
只记录斜率,把“比前面所有数都大的数”称为“优数”,那么答案即为“优数”的个数
那么线段树每个节点维护最大值\(max\)和区内“优数”的个数\(ans\)。
先考虑查询。我们把查询写成\(q(o, x)\)表示查询\([l_o,r_o]\)区间(即结点\(o\)代表的区间)内比\(x\)大的“优数”的个数。
如果\(x\)大于等于\(max_{lson}\),那么\(q(o,x)=q(rson, x)\)。显然。
否则,\(q(o,x)=ans_o - (ans_{lson}-q(lson, x))\),即总“优数”个数减去左子区间里小于等于x的“优数”个数。
再考虑如何维护信息。\(max\)容易维护。\(ans_o=ans_{lson}+q(rson, max_{lson})\)即可。
最终的答案就是\(q(root, 0)\)。
Code
#include <algorithm>
#include <cstdio>
const int N = 100050;
typedef long long LL;
struct Frac{int x, y;Frac(int x = 1, int y = 0) : x(x), y(y) {}bool operator<(const Frac &f) const {return (LL)y * f.x < (LL)f.y * x;}
}maxv[N * 4];
int lenv[N * 4], Y[N];
int query(int o, int l, int r, Frac x) {if (!(x < maxv[o])) return 0;if (l == r) return 1;int mid = (l + r) / 2;return maxv[o << 1] < x? query(o << 1 | 1, mid + 1, r, x): query(o << 1, l, mid, x) + lenv[o] - lenv[o << 1];
}
void upd(int o, int l, int r) {if (l == r) {lenv[o] = 1;maxv[o] = Frac(l, Y[l]);} else {int lc = o << 1, rc = o << 1 | 1, mid = (l + r) / 2;maxv[o] = std::max(maxv[lc], maxv[rc]);lenv[o] = lenv[lc] + query(rc, mid + 1, r, maxv[lc]);}
}
void modify(int o, int l, int r, int x, int y) {if (l > x || r < x) return;if (l == r)Y[x] = y;else {int mid = (l + r) / 2;modify(o << 1, l, mid, x, y);modify(o << 1 | 1, mid + 1, r, x, y);}upd(o, l, r);
}
void build(int o, int l, int r) {maxv[o] = Frac(l, 0); lenv[o] = 1;if (l != r) {int mid = (l + r) / 2;build(o << 1, l, mid);build(o << 1 | 1, mid + 1, r);}
}
int main() {int n, m, x, y;scanf("%d%d", &n, &m);build(1, 1, n);while (m--) {scanf("%d%d", &x, &y);modify(1, 1, n, x, y);printf("%d\n", query(1, 1, n, Frac()));}return 0;
}
转载于:https://www.cnblogs.com/y-clever/p/8513175.html
BZOJ2957 楼房重建相关推荐
- [BZOJ2957]楼房重建
楼房重建 题解 很容易发现,一个楼房能够被看到当且仅当它前面的楼房的斜率都比它的小. 我们显然可以把斜率这东西离散化下来,当成一个权值,所以我们相当于要事实维护有多少个不同的前缀最大值. 首先这应该很 ...
- BZOJ2957:楼房重建(线段树)
Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些 ...
- BZOJ2957楼房重建
传送门 https://www.luogu.org/problemnew/show/P4198 蒟蒻渣渣禹看到这个题时十分不想写线段树emmmm 于是乎....分块!!! 分块.思路就是:如果一个楼 ...
- Bzoj2957: 楼房重建
题目 传送门 Sol 线段树,维护斜率单增的最高点和长度 更新,以下的都是指斜率 当前点的左儿子更新上来,右儿子递归 如果右儿子的左儿子的最大值大于左儿子的 加上算出右儿子的右儿子的贡献(右儿子贡献减 ...
- bzoj-2957 楼房重建
题意: 数轴上有n个楼,分别在1~n这些点上: m次查询.每次改变一个楼的高度,问从(0,0)这个点能够看到多少楼: 题解: 对于一个楼来说要想看到这个楼.那么前面的楼的斜率一定比这个楼小: 那么考虑 ...
- BZOJ 2957楼房重建
传送门 线段树 //Twenty #include<cstdio> #include<cstdlib> #include<iostream> #include< ...
- P4198 楼房重建 线段树 + 区间合并
传送门 文章目录 题意: 思路: 题意: 题面有点问题,按照人类正常的理解来就好啦. 思路: 可以想到维护每个位置的一个斜率,模拟的话就是从第一个位置开始向后选,当某个位置斜率大于当前位置的时候,答案 ...
- LG P4198 楼房重建(线段树)
LG P4198 楼房重建 Solution 基础的线段树题,虽然我还不熟练就是了. 大概就是单点修改,求全局的极大子序列. 我们需要维护一个区间最大值aaa和极大子序列长度sss. 合并xxx的左右 ...
- [luogu P4198] 楼房重建(线段树 + 思维)
luogu 楼房重建 problem solution code problem 洛谷链接 solution 非常巧妙的一道题,对线段树的运用很灵活. 显然这个与原点的连线可以想到将每个点转化为与原点 ...
最新文章
- Docker的安装和使用及其Docker容器间通信,云计算技术与应用实验报告
- Linux下使用命令生成二维码
- RabbitMQ简单介绍+Windows环境安装
- 微课|中学生可以这样学Python(例5.6、例5.7):集合应用
- 从QQ空间热度分析看社区营销
- 诺基亚指控联想侵权;格力回应“被中国移动取消中标资格”;微软暂停更新 Edge 浏览器 | 极客头条...
- CISA《网络安全事件和漏洞响应手册》提到的SSVC是什么?
- .NET Core 中读取appsettings.json配置文件的方法
- 如何学习UG编程?零基础入门学UG难吗
- oeasy教您玩转vim - 2 - # 使用帮助
- java 水晶按钮_java渲染水晶按钮
- 安卓手机云控系统框架源码,PHP+Autojs, ,这套是空框架源码
- 电脑怎么设置时间自动关机?
- xp此计算机无法连接到,XP系统无法连接到网络怎么办
- 从钉钉后台API获取企业通信录
- LabVIEW笔记(一)
- Oracle SQL前三行,后三行
- python实现txt转word
- 用Adobe Reader PDF阅读器来验证电子签名有效性
- c语言程序设计教程中国农业出版社答案,C语言程序设计教程杨路明课后习题答案北京邮电大学出版社.pdf...
热门文章
- 统计一个长度为2的子字符串在另一个字符串中出现的次数.例如:假定输入的字符串为“asd asasdfg asd as zx67 asd mklo”,子字符串为“as”,函数返回值为6。
- python核心编程第三版_《Python核心编程(第3版)》
- Java企业面试算法新得体会之5字符串问题24问
- Java消息中间件--ActiveMq,RabbitMQ,Kafka
- mysql主从复制 读写分离
- Bootstrap研究3-基础html元素
- 清结算内部勾兑业务一个比较有意思的问题整理
- pytorch中的gather函数_Pytorch中Emdedding函数的解释及使用方法
- Go面试题 | []int 能转换为 []interface 吗?
- Rand7()实现Rand10()