/**
 * 考虑到题目要求时间复杂度为O(n),如果直接使用Map的话,排序的时间复杂度就会增加到O(nlogn),所以自定义一个数据结构
 * orderedMap.orderedEntries 的返回值,按照key(number类型)进行排序,从小到大
 */
class OrderedMap {
  constructor() {
    /** 使用map数据结构,查找的时间复杂度为O(1) */
    this.map = new Map()
    /**
     * 额外维护一份数组的数据结构,按照key的顺序进行插入
     * 就不采用map.entries().sort()方式来获取了
     */
    this.orderedEntries = []
  }
 
  has(key) {
    return this.map.has(key)
  }
 
  get(key) {
    return this.map.get(key)
  }
 
  /** 时间复杂度O(n),这个是为了维护一个有序的数组 */
  set(key, value) {
    /** 已经存在的情况 */
    if (this.map.has(key)) {
      const idx = this.orderedEntries.findIndex(([_key, _value]) => _key === key)
      this.orderedEntries[idx] = [key, value]
      this.map.set(key, value)
      return
    }
 
    /** 没有存在的情况,就简单的采用迭代遍历了,可以考虑使用二分进行优化 */
    let idx = -1 // 最后一个小于“权重”的下标
    for (let _index in this.orderedEntries) {
      const [_key, _value] = this.orderedEntries[_index]
      if (_key >= key) break
      idx++
    }
    this.orderedEntries.splice(idx + 1, 0, [key, value])
 
    this.map.set(key, value)
  }
 
  delete(key) {
    this.map.delete(key)
 
    const idx = this.orderedEntries.findIndex(([_key]) => _key === key)
    if (idx > -1) this.orderedEntries.splice(idx, 1)
  }
 
  entries() {
    return this.orderedEntries
  }
}
 
class IntensitySegments {
  constructor() {
    /**
     * 维护每个点的高度的相对增量的map
     * key为位置信息,pos
     * value为高度的相对增量
     */
    this.heightDiffMap = new OrderedMap()
  }
 
  /** 封装下set方法,当key对应的高度增量为0的时候,,就需要干掉key(表示该位置是冗余信息) */
  #setHeightDiffMap(key, value) {
    this.heightDiffMap.set(key, value)
    if (value === 0) this.heightDiffMap.delete(key)
  }
 
  add(from, to, amount) {
    this.#check(from, to)
    this.#setHeightDiffMap(from, (this.heightDiffMap.get(from) || 0) + amount)
    this.#setHeightDiffMap(to, (this.heightDiffMap.get(to) || 0) - amount)
  }
 
  set(from, to, amount) {
    this.#check(from, to)
    const leftHeight = this.#getLeftHeightOfPos(from)
    const rightHeight = this.#getRightHeightOfPos(to)
 
    // 删除老的高度增量,在[from, to]区间内
    this.heightDiffs.forEach(([pos]) => {
      if (from <= pos && pos <= to) {
        this.heightDiffMap.delete(pos)
      }
    })
 
    // 添加新的高度增量
    this.#setHeightDiffMap(from, amount - leftHeight)
    this.#setHeightDiffMap(to, rightHeight - amount)
  }
 
  toString() {
    return JSON.stringify(this.heights)
  }
 
  #check(from, to) {
    if (from >= to) throw new Error(`from的值必须要小于to的值, 当前from为${from}, to为${to}`)
  }
 
  /**
   * 返回的是一个有序的数组,时间复杂度为O(n)
   * @return Array<[number(位置信息), number(高度的相对增量)]>
   */
  get heightDiffs() {
    return [...this.heightDiffMap.entries()]
  }
 
  /**
   * @return Array<[number(位置信息), number(高度信息)]>
   */
  get heights() {
    const heights = []
 
    // 从0开始,根据高度的增量信息不断累加
    let current = 0
    this.heightDiffs.forEach(([pos, amount]) => {
      current += amount
      heights.push([pos, current])
    })
 
    return heights
  }
 
  /** 获取某个位置左边(线段)的高度 */
  #getLeftHeightOfPos(targetPos) {
    // 从无穷小的0开始迭代
    let prevPos = -Infinity
    let prevHeight = 0
 
    for (let [currPos, height] of this.heights) {
      // (注意左开右闭)如果目标位置在“上一个位置”和“当前位置”之间,那么目标左侧的高度就是上一个高度
      if (prevPos < targetPos && targetPos <= currPos) {
        return prevHeight
      }
 
      prevPos = currPos
      prevHeight = height
    }
 
    return prevHeight // 如果匹配到最后也没找到,就返回最后的高度
  }
 
  /** 获取某个位置右边(线段)的高度 */
  #getRightHeightOfPos(targetPos) {
    // 从无穷小的0开始迭代
    let prevPos = -Infinity
    let prevHeight = 0
 
    for (let [currPos, height] of this.heights) {
      // (注意左闭右开)如果目标位置在“上一个位置”和“当前位置”之间,那么目标右侧的高度就是上一个高度
      if (prevPos <= targetPos && targetPos < currPos) {
        return prevHeight
      }
 
      prevPos = currPos
      prevHeight = height
    }
 
    return prevHeight // 如果匹配到最后也没找到,就返回最后的高度
  }
}