洛谷 P4198 楼房重建

该博客介绍了如何解决洛谷P4198题目,即如何利用区间单调栈处理楼房重建问题。文章详细阐述了如何将原问题转化为求区间单调栈大小,并讨论了如何进行区间合并,特别是提出了`calc`函数的实现,用于计算合并后的单调栈大小。通过优化`calc`函数,实现了在O(Qlog2n)的时间复杂度内解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路

此题可转化为以下模型

给定序列 a [ 1... n ] a[1...n] a[1...n],支持单点修改,每次求区间单调栈大小

n , Q ≤ 1 0 5 n,Q\le 10^5 n,Q105

区间单调栈是什么呢?对于一个区间,建立一个栈,首先将第一个元素入栈,从左往右扫,如果当前元素大于等于栈顶元素,就将其入栈,由此形成的栈即为单调不减的区间单调栈。

转化一下,其实就是求区间内满足 a [ i ] = max ⁡ j = 1 i a [ j ] a[i]=\max\limits_{j=1}^ia[j] a[i]=j=1maxia[j] a [ i ] a[i] a[i]的个数。

一个自然的想法是维护单调栈的大小 s i z siz siz,那么如何去进行区间的合并呢?

合并两个子区间时,假设左子区间为 L L L,右子区间为 R R R,考虑合并之后的单调栈的组成部分:

  • 第一部分: L L L的单调栈

    因为单调栈是从左往右做的,所以 L L L的单调栈必然是大区间单调栈的一部分

  • 剩余部分

    设出函数 c a l c ( n o w , p r e ) calc(now,pre) calc(now,pre) n o w now now表示当前节点, p r e pre pre表示当前单调栈的栈顶, c a l c calc calc函数计算剩余部分的单调栈的大小

总的单调栈大小 s i z siz siz就是 L s i z + c a l c ( R , L m a x ) L_{siz}+calc(R,L_{max}) Lsiz+calc(R,Lmax)

calc的实现

现在有 c a l c ( n o w , p r e ) calc(now,pre) calc(now,pre) l l l表示 n o w now now的左子树, r r r表示 n o w now now的右子树

  • 如果 p r e > l m a x pre>l_{max} pre>lmax,说明整个左子区间都不用考虑了,此时答案就变成了 c a l c ( r , p r e ) calc(r,pre) calc(r,pre)
  • 如果 p r e ≤ l m a x pre\le l_{max} prelmax,此时 l l l是有贡献的,他对 s i z siz siz的贡献就是 c a l c ( l , p r e ) calc(l,pre) calc(l,pre),右子树的贡献为 c a l c ( r , l m a x ) calc(r,l_{max}) calc(r,lmax),总贡献就是 c a l c ( l , p r e ) + c a l c ( r , l m a x ) calc(l,pre)+calc(r,l_{max}) calc(l,pre)+calc(r,lmax)

至此 c a l c calc calc就推完了,但是我们发现如果仅仅是这样的话,在最坏的情况下,复杂度会爆炸,那么怎么优化呢?

观察 c a l c ( r , l m a x ) calc(r,l_{max}) calc(r,lmax),发现它就等于 s i z − l s i z siz-l_{siz} sizlsiz,所以第二种情况就可以变成 c a l c ( l , p r e ) + s i z − l s i z calc(l,pre)+siz-l_{siz} calc(l,pre)+sizlsiz,其中 s i z siz siz都是可以处理好的

这样我们就可以在 O ( log ⁡ n ) O(\log n) O(logn)的时间里完成一次合并

总时间复杂度 O ( Q log ⁡ 2 n ) O(Q\log^2 n) O(Qlog2n)

代码

/*
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';
  }
}
内容概要:本文详细探讨了基于樽海鞘算法(SSA)优化的极限学习机(ELM)在回归预测任务中的应用,并与传统的BP神经网络、广义回归神经网络(GRNN)以及未优化的ELM进行了性能对比。首先介绍了ELM的基本原理,即通过随机生成输入层与隐藏层之间的连接权重及阈值,仅需计算输出权重即可快速完成训练。接着阐述了SSA的工作机制,利用樽海鞘群体觅食行为优化ELM的输入权重和隐藏层阈值,从而提高模型性能。随后分别给出了BP、GRNN、ELM和SSA-ELM的具体实现代码,并通过波士顿房价数据集和其他工业数据集验证了各模型的表现。结果显示,SSA-ELM在预测精度方面显著优于其他三种方法,尽管其训练时间较长,但在实际应用中仍具有明显优势。 适合人群:对机器学习尤其是回归预测感兴趣的科研人员和技术开发者,特别是那些希望深入了解ELM及其优化方法的人。 使用场景及目标:适用于需要高效、高精度回归预测的应用场景,如金融建模、工业数据分析等。主要目标是提供一种更为有效的回归预测解决方案,尤其是在处理大规模数据集时能够保持较高的预测精度。 其他说明:文中提供了详细的代码示例和性能对比图表,帮助读者更好地理解和复现实验结果。同时提醒使用者注意SSA参数的选择对模型性能的影响,建议进行参数敏感性分析以获得最佳效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值