洛谷 P4198 楼房重建
思路
此题可转化为以下模型
给定序列\(a[1...n]\),支持单点修改,每次求区间单调栈大小
\(n,Q\le 10^5\)
区间单调栈是什么呢?对于一个区间,建立一个栈,首先将第一个元素入栈,从左往右扫,如果当前元素大于等于栈顶元素,就将其入栈,由此形成的栈即为单调不减的区间单调栈。
转化一下,其实就是求区间内满足\(a[i]=\max\limits_{j=1}^ia[j]\)的\(a[i]\)的个数。
一个自然的想法是维护单调栈的大小\(siz\),那么如何去进行区间的合并呢?
合并两个子区间时,假设左子区间为\(L\),右子区间为\(R\),考虑合并之后的单调栈的组成部分:
第一部分:\(L\)的单调栈
因为单调栈是从左往右做的,所以\(L\)的单调栈必然是大区间单调栈的一部分
剩余部分
设出函数\(calc(now,pre)\),\(now\)表示当前节点,\(pre\)表示当前单调栈的栈顶,\(calc\)函数计算剩余部分的单调栈的大小
总的单调栈大小\(siz\)就是\(L_{siz}+calc(R,L_{max})\)
calc的实现
现在有\(calc(now,pre)\),\(l\)表示\(now\)的左子树,\(r\)表示\(now\)的右子树
- 如果\(pre>l_{max}\),说明整个左子区间都不用考虑了,此时答案就变成了\(calc(r,pre)\)
- 如果\(pre\le l_{max}\),此时\(l\)是有贡献的,他对\(siz\)的贡献就是\(calc(l,pre)\),右子树的贡献为\(calc(r,l_{max})\),总贡献就是\(calc(l,pre)+calc(r,l_{max})\)
至此\(calc\)就推完了,但是我们发现如果仅仅是这样的话,在最坏的情况下,复杂度会爆炸,那么怎么优化呢?
观察\(calc(r,l_{max})\),发现它就等于\(siz-l_{siz}\),所以第二种情况就可以变成\(calc(l,pre)+siz-l_{siz}\),其中\(siz\)都是可以处理好的
这样我们就可以在\(O(\log n)\)的时间里完成一次合并
总时间复杂度\(O(Q\log^2 n)\)
代码
/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
double val;
int n, m, ans, pos;
struct node { double maxn; int siz; } a[A << 2];
void build(int rt, int l, int r) {
if (l == r) return;
int mid = (l + r) >> 1;
build(lson, l, mid), build(rson, mid + 1, r);
}
inline int calc(int rt, int l, int r, double h) {
if (l == r) return a[rt].maxn > h;
int mid = (l + r) >> 1;
if (a[lson].maxn <= h) return calc(rson, mid + 1, r, h);
return calc(lson, l, mid, h) + a[rt].siz - a[lson].siz;
}
inline void update(int rt, int l, int r) {
if (l == r) {
a[rt].maxn = val, a[rt].siz = 1;
return;
}
int mid = (l + r) >> 1;
if (pos <= mid) update(lson, l, mid);
else update(rson, mid + 1, r);
a[rt].maxn = max(a[lson].maxn, a[rson].maxn);
a[rt].siz = a[lson].siz + calc(rson, mid + 1, r, a[lson].maxn);
}
int main() {
n = read(), m = read();
build(1, 1, n);
while (m--) {
int x = read(), y = read();
pos = x, val = (double) y / x;
update(1, 1, n);
cout << a[1].siz << '\n';
}
}
洛谷 P4198 楼房重建的更多相关文章
- 洛谷P4198 楼房重建 (分块)
洛谷P4198 楼房重建 题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题, ...
- 洛谷 P4198 楼房重建 题解
题面 首先你要知道题问的是什么:使用一种数据结构,动态地维护以1为起点地最长上升子序列(把楼房的高度转化成斜率地序列)的长度: 怎么做?线段树! 我们在线段树上维护两个东西:1.这个区间内斜率的最大值 ...
- 洛谷P4198 楼房重建 单调栈+线段树
正解:单调栈+线段树 解题报告: 传送门! 首先考虑不修改的话就是个单调栈板子题昂,这个就是 然后这题的话,,,我怎么记得之前考试好像有次考到了类似的题目昂,,,?反正我总觉着这方法似曾相识的样子,, ...
- 洛谷P4198 楼房重建(线段树)
题意 题目链接 Sol 别问我为什么发两遍 就是为了骗访问量 这个题的线段树做法,,妙的很 首先一个显然的结论:位置\(i\)能被看到当且仅当\(\frac{H_k}{k} < \frac{H_ ...
- 洛谷P4198 楼房重建
题意:给定序列,每次修改一个值,求前缀最大值的个数. 解:线段树经典应用. 每个节点维护最大值和该区间前缀最大值个数. 发现我们不用下传标记,只需要合并区间. 需要实现一个函数int ask([l r ...
- 洛谷 P4198 楼房重建 线段树维护单调栈
P4198 楼房重建 题目链接 https://www.luogu.org/problemnew/show/P4198 题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上 ...
- P4198 楼房重建
P4198 楼房重建 集中写博客= = 首先把高度变成斜率 然后就比较玄学了,首先用线段树维护一个区间的斜率最大值,和只看这个区间时能看见的楼房个数ans 然后更新时先更新max,再处理神奇的ans ...
- 洛谷P1119-灾后重建-floyd算法
洛谷P1119-灾后重建 题目描述 给出\(B\)地区的村庄数NN,村庄编号从\(0\)到\(N-1\),和所有\(M\)条公路的长度,公路是双向的. 给出第\(i\)个村庄重建完成的时间\(t_i\ ...
- 洛谷 P3905 道路重建
题目描述 从前,在一个王国中,在n个城市间有m条道路连接,而且任意两个城市之间至多有一条道路直接相连.在经过一次严重的战争之后,有d条道路被破坏了.国王想要修复国家的道路系统,现在有两个重要城市A和B ...
随机推荐
- Django框架09 /ajax、crsf、settings导入
Django框架09 /ajax.crsf.settings导入 目录 Django框架09 /ajax.crsf.settings导入 1. ajax概述 2. ajax应用 3. ajax上传文件 ...
- Python基础最难知识点:正则表达式(使用步骤)
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 正则表达式,简称regex,是文本模式的描述方法.你可以在google上搜 ...
- JavaScript定时器及回调用法
JavaScript定时器及回调用法 循环定时任务 // 假设现在有这样一个需求:我需要请求一个接口,根据返回结果判断需不需要重复请求,直到达到某一条件为止,停止请求执行某操作 <script ...
- 学Python常用数据结构之字典
迄今为止,我们已经为大家介绍了Python中的三种容器型数据类型,但是这些数据类型还不足以帮助我们解决所有的问题.例如,我们要保存一个人的信息,包括姓名.年龄.体重.单位地址.家庭住址.本人手机号.紧 ...
- python学习03-使用动态ua
在写爬虫的时候要使用到浏览器ua 分享一下今天学到的如何使用动态ua的进行爬取 1.简单的爬取网页信息 from urllib.request import urlopen #目标地址 url = & ...
- 区间dp复习 之 tyvj 1198 矩阵连乘
题目描述 一个\(n*m\)矩阵由\(n\)行\(m\)列共\(n*m\)个数排列而成.两个矩阵\(A\)和\(B\)可以相乘当且仅当\(A\)的列数等于\(B\)的行数.一个\(N*M\)的矩阵乘以 ...
- 在docker中写个Hello World
Hello World Docker 示例 准备hello.cpp #include<stdio.h> int main(){ printf("Hello World Docke ...
- 用x种方式求第n项斐波那契数,99%的人只会第一种
大家好啊,我们又见面了.听说有人想学数据结构与算法却不知道从何下手?那你就认真看完本篇文章,或许能从中找到方法与技巧. 本期我们就从斐波那契数列的几种解法入手,感受算法的强大与奥妙吧. 原文链 ...
- django-rest-framework-源码解析001-整体框架
简介 Django Rest Framework是一个强大且灵活的工具包,主要用以构建RESTful风格的Web API. Django REST Framework(简称DRF)可以在Django的 ...
- Springboot(一)springboot简介与入门程序
一.springboot简介: 对spring框架盛行了多年的java方向开发人员来说,每个人java开发已经把spring框架当做开发中不可或缺的一部分. 之前传统的模式都是以application ...