Problem p02904 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
using namespace std;
using lint = long long int;

struct UnionFind {
  vector<int> data;
  UnionFind(int n) { data.assign(n, -1); }

  bool unite(int x, int y) {
    x = root(x), y = root(y);
    if (x == y)
      return true;
    if (data[x] > data[y])
      swap(x, y);
    data[x] += data[y];
    data[y] = x;
    return true;
  }

  int root(int x) { return (data[x] < 0 ? x : data[x] = root(data[x])); }

  int size(int x) { return -data[root(x)]; }
};

struct SegmentTree {
  using D = long long int;
  using DD = function<D(D, D)>;

private:
  int n;
  vector<D> data;
  D ie;
  DD f;

public:
  SegmentTree(int len, D ie, DD f) : ie(ie), f(f) {
    n = pow(2, ceil(log2(len)));
    data.assign(2 * n, ie);
  }

  void update(int idx, D val) {
    idx += n;
    data[idx] = val;
    while (idx) {
      idx >>= 1;
      data[idx] = f(data[idx * 2], data[idx * 2 + 1]);
    }
  }

  // [l, r)
  D query(int l, int r) {
    l = min(max(l, 0), n);
    r = min(max(r, 0), n);
    D res = ie;
    for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
      if (l & 1)
        res = f(res, data[l++]);
      if (r & 1)
        res = f(res, data[--r]);
    }
    return res;
  }

  D operator[](int i) { return data[i + n]; }
};

int main() {
  lint n, k;
  cin >> n >> k;

  vector<lint> p(n);
  for (auto &elem : p)
    cin >> elem;

  UnionFind uf(n - k + 1);

  // i+k <= j
  static vector<lint> inc(n, 1);
  for (lint i = 0; i < n; i++) {
    if (p[i] < p[i + 1])
      inc[i + 1] = inc[i] + 1;
  }
  static vector<lint> po;
  for (lint i = 0; i + k - 1 < n; i++) {
    if (inc[i + k - 1] - inc[i] == k - 1)
      po.push_back(i);
  }
  for (lint i = 0; i + 1 < po.size(); i++) {
    uf.unite(po[i], po[i + 1]);
  }

  // i < j < i+k
  // 隣接間だけチェックすればよい
  SegmentTree mn(n, 1e18, [](lint a, lint b) { return min(a, b); });
  SegmentTree mx(n, -1e18, [](lint a, lint b) { return max(a, b); });
  for (lint i = 0; i < n; i++) {
    mn.update(i, p[i]);
    mx.update(i, p[i]);
  }

  for (lint i = 0; i + 1 + k <= n; i++) {
    if (p[i] < mn.query(i + 1, i + k) && mx.query(i + 1, i + k) < p[i + k]) {
      uf.unite(i, i + 1);
    }
  }

  map<lint, lint> mp;
  for (lint i = 0; i < n - k + 1; i++)
    mp[uf.root(i)]++;
  cout << mp.size() << endl;
}

Fixed submission:
#include <bits/stdc++.h>
using namespace std;
using lint = long long int;

struct UnionFind {
  vector<int> data;
  UnionFind(int n) { data.assign(n, -1); }

  bool unite(int x, int y) {
    x = root(x), y = root(y);
    if (x == y)
      return true;
    if (data[x] > data[y])
      swap(x, y);
    data[x] += data[y];
    data[y] = x;
    return true;
  }

  int root(int x) { return (data[x] < 0 ? x : data[x] = root(data[x])); }

  int size(int x) { return -data[root(x)]; }
};

struct SegmentTree {
  using D = long long int;
  using DD = function<D(D, D)>;

private:
  int n;
  vector<D> data;
  D ie;
  DD f;

public:
  SegmentTree(int len, D ie, DD f) : ie(ie), f(f) {
    n = pow(2, ceil(log2(len)));
    data.assign(2 * n, ie);
  }

  void update(int idx, D val) {
    idx += n;
    data[idx] = val;
    while (idx) {
      idx >>= 1;
      data[idx] = f(data[idx * 2], data[idx * 2 + 1]);
    }
  }

  // [l, r)
  D query(int l, int r) {
    l = min(max(l, 0), n);
    r = min(max(r, 0), n);
    D res = ie;
    for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
      if (l & 1)
        res = f(res, data[l++]);
      if (r & 1)
        res = f(res, data[--r]);
    }
    return res;
  }

  D operator[](int i) { return data[i + n]; }
};

int main() {
  lint n, k;
  cin >> n >> k;

  vector<lint> p(n);
  for (auto &elem : p)
    cin >> elem;

  UnionFind uf(n - k + 1);

  // i+k <= j
  static vector<lint> inc(n, 1);
  for (lint i = 0; i + 1 < n; i++) {
    if (p[i] < p[i + 1])
      inc[i + 1] = inc[i] + 1;
  }
  static vector<lint> po;
  for (lint i = 0; i + k - 1 < n; i++) {
    if (inc[i + k - 1] - inc[i] == k - 1)
      po.push_back(i);
  }
  for (lint i = 0; i + 1 < po.size(); i++) {
    uf.unite(po[i], po[i + 1]);
  }

  // i < j < i+k
  // 隣接間だけチェックすればよい
  SegmentTree mn(n, 1e18, [](lint a, lint b) { return min(a, b); });
  SegmentTree mx(n, -1e18, [](lint a, lint b) { return max(a, b); });
  for (lint i = 0; i < n; i++) {
    mn.update(i, p[i]);
    mx.update(i, p[i]);
  }

  for (lint i = 0; i + 1 + k <= n; i++) {
    if (p[i] < mn.query(i + 1, i + k) && mx.query(i + 1, i + k) < p[i + k]) {
      uf.unite(i, i + 1);
    }
  }

  map<lint, lint> mp;
  for (lint i = 0; i < n - k + 1; i++)
    mp[uf.root(i)]++;
  cout << mp.size() << endl;
}