• IOI2018 meetings


    萌新瞎想了很直接的 \(\Theta(nq)\)(在 \(\rm Luogu\) 上过了) 和一个 \(\Theta(n \log n +q \log^3 n)\) (在 \(\rm UOJ\) 上过了)的做法,就写篇题解吧。

    \(\rm UOJ\) 过了的做法在 \(\rm Luogu\) 上过不去应该是因为洛谷空间开小了。

    题意

    给定长度为 \(n\) 的序列 \(h\)\(q\) 次询问,每次给定区间 \([l,r]\),你要在 \([l,r]\) 中选出一个位置 \(x\) 举行会议,使得 \(\sum\limits_{l \le i \le r} \max_{j \in [\min(i,x),\max(i,x)]} h_j\) 最小。

    数据范围:\(1 \le n, q \le 7.5 \times 10^5\)\(1 \le h_i \le 10^9\)

    题解

    首先考虑暴力怎么做:每次找到区间中的 \(\rm max\),然后枚举是把会议丢 \(\rm max\) 的左边还是丢右边即可,问题就被分成了两半。

    考虑优化,先找到整个区间的最大值,然后把问题切成两半。不妨考虑左边那一半怎么做。

    考虑先建出左边那半的单调栈。设栈中元素为 \(S_1,S_2,S_3,...,S_k\)

    其中 \(h_{S_i} \le h_{S_{i+1}}\)\(S_1 = l\)\(S_k = r\)

    枚举我们选择的会议处于栈中哪两个元素之间。假设设在 \([S_x,S_{x+1})\) 中。

    那么:

    1. \([l,S_x)\) 的贡献均为 \(S_x\)
    2. \([S_{x+1},r)\) 中一个元素的贡献只和该元素在栈中哪两个元素之间有关。
    3. 由于 \(x+1\)\(x\) 后面第一个值 \(> h_x\) 的元素,因此 \([S_x,S_{x+1})\) 中元素的贡献可以预处理(找到 \((S_x,S_{x+1})\) 中的最大值,然后可以递归成形式相同的子问题)。

    于是我们就会 \(\Theta(nq)\) 了。

    直接写是过不去的。我们预处理出 \(fa_i\)\(i\) 后第一个 \(> h_i\) 的元素。

    然后从 \(l\) 开始暴力跳 \(fa\) 跳到 \(r\) 就过了。

    \(n^2\) 过百万,暴力碾标算!

    观察我们的暴力是怎么完成的:其实是求了树上一条链的 \(\max(k_ix+b_i)\)

    于是可以树剖,转化为序列上区间 \(\max(k_ix+b_i)\)。建颗线段树,每个线段树上的节点 \([L,R]\) 维护一颗李超树即可。

    为了优化复杂度,\([L,R]\) 上的李超树可以用 \([L,mid]\)\((mid+1,R]\) 的李超树合并。

    其实可以用 XJOI4182 的套路优化到 \(\Theta(n \log n + q \log^2 n)\),不过我懒就没写

    aclink

    感觉这种思路也是可以再优化的,毕竟链上的元素是有单调性的。

    祝大家学习愉快!

  • 相关阅读:
    例行更新,防止被踢
    C语言 遍历磁盘目录
    析构函数的调用
    数组学习笔记
    函数学习笔记
    c++语言 纯虚函数的使用
    c++语言 内联方法
    复制构造函数
    c++语言 覆盖成员函数
    面向对象程序设计
  • 原文地址:https://www.cnblogs.com/zkyJuruo/p/15666789.html
Copyright © 2020-2023  润新知