🪴 あやめHex

Search

Search IconIcon to open search

Segment tree beats

Last updated Nov 30, 2022 Edit Source

# 説明

# 計算量

# 実装

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
#include <algorithm>
#include <cassert>
#include <iostream>
#include <vector>
using namespace std;

using ll = long long;
#define N 10003

class SegmentTreeBeats {
  const ll inf = 1e18;
  int n, n0;
  ll max_v[4 * N], smax_v[4 * N];
  ll sum[4 * N], max_c[4 * N];

  void update_node_max(int k, ll x) {
    sum[k] += (x - max_v[k]) * max_c[k];
    max_v[k] = x;
  }

  void push(int k) {
    if (max_v[k] < max_v[2 * k + 1]) update_node_max(2 * k + 1, max_v[k]);
    if (max_v[k] < max_v[2 * k + 2]) update_node_max(2 * k + 2, max_v[k]);
  }

  void update(int k) {
    sum[k] = sum[2 * k + 1] + sum[2 * k + 2];

    if (max_v[2 * k + 1] < max_v[2 * k + 2]) {
      max_v[k] = max_v[2 * k + 2];
      max_c[k] = max_c[2 * k + 2];
      smax_v[k] = max(max_v[2 * k + 1], smax_v[2 * k + 2]);
    } else if (max_v[2 * k + 1] > max_v[2 * k + 2]) {
      max_v[k] = max_v[2 * k + 1];
      max_c[k] = max_c[2 * k + 1];
      smax_v[k] = max(smax_v[2 * k + 1], max_v[2 * k + 2]);
    } else {
      max_v[k] = max_v[2 * k + 1];
      max_c[k] = max_c[2 * k + 1] + max_c[2 * k + 2];
      smax_v[k] = max(smax_v[2 * k + 1], smax_v[2 * k + 2]);
    }
  }

  void _update_min(ll x, int a, int b, int k, int l, int r) {
    if (b <= l || r <= a || max_v[k] <= x) return;
    if (a <= l && r <= b && smax_v[k] < x) {
      update_node_max(k, x);
      return;
    }

    push(k);
    _update_min(x, a, b, 2 * k + 1, l, (l + r) / 2);
    _update_min(x, a, b, 2 * k + 2, (l + r) / 2, r);
    update(k);
  }

  ll _query_max(int a, int b, int k, int l, int r) {
    if (b <= l || r <= a) return 0;
    if (a <= l && r <= b) return max_v[k];
    push(k);
    ll lv = _query_max(a, b, 2 * k + 1, l, (l + r) / 2);
    ll rv = _query_max(a, b, 2 * k + 2, (l + r) / 2, r);
    return max(lv, rv);
  }

  ll _query_sum(int a, int b, int k, int l, int r) {
    if (b <= l || r <= a) return 0;
    if (a <= l && r <= b) return sum[k];
    push(k);
    ll lv = _query_sum(a, b, 2 * k + 1, l, (l + r) / 2);
    ll rv = _query_sum(a, b, 2 * k + 2, (l + r) / 2, r);
    return lv + rv;
  }

public:
  SegmentTreeBeats(int n) { SegmentTreeBeats(n, nullptr); }

  SegmentTreeBeats(int n, ll *a) : n(n) {
    n0 = 1;
    while (n0 < n) n0 <<= 1;

    for (int i = 0; i < n; ++i) {
      max_v[n0 - 1 + i] = sum[n0 - 1 + i] = (a != nullptr ? a[i] : 0);
      smax_v[n0 - 1 + i] = -inf;
      max_c[n0 - 1 + i] = 1;
    }

    for (int i = n; i < n0; ++i) {
      max_v[n0 - 1 + i] = smax_v[n0 - 1 + i] = -inf;
      sum[n0 - 1 + i] = max_c[n0 - 1 + i] = 0;
    }
    for (int i = n0 - 2; i >= 0; i--) update(i);
  }

  // range minimize query
  void update_min(int a, int b, ll x) { return _update_min(x, a, b, 0, 0, n0); }

  // range maximum query
  ll query_max(int a, int b) { return _query_max(a, b, 0, 0, n0); }

  // range sum query
  ll query_sum(int a, int b) { return _query_sum(a, b, 0, 0, n0); }
};

# 使用例