Problem p02904 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>

#ifdef __LOCAL
#define DBG(X) cout << #X << " = " << (X) << endl;
#define SAY(X) cout << (X) << endl;
#else
#define DBG(X)
#define SAY(X)
#endif

#ifdef __LOCAL
#include <filesystem>
namespace fs = std::filesystem;
#endif

using namespace std;

using ll = long long int;
using ull = unsigned long long int;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

int dx[] = {1, 0, -1, 0, 0};
int dy[] = {0, 1, 0, -1, 0};
const int INT_INF = (int)(2e9);
const ll LL_INF = (ll)(2e18);

inline void fast_io() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr);
};
template <typename T, typename S>
inline ostream &operator<<(ostream &os, const pair<T, S> p) {
  cout << "[" << p.first << ";" << p.second << "]";
  return os;
}
template <typename T>
inline ostream &operator<<(ostream &os, const vector<T> &v) {
  for (auto el : v)
    cout << el << " ";
  return os;
}
template <typename T> inline vector<T> fetch_vec(int sz) {
  vector<T> ret(sz);
  for (auto &elem : ret)
    cin >> elem;
  return ret;
}

template <typename Monoid> struct SegmentTree {
  using F = function<Monoid(Monoid, Monoid)>;

  int sz;
  vector<Monoid> seg;

  const F f;
  const Monoid M1;

  SegmentTree(int n, const F f, const Monoid &M1) : f(f), M1(M1) {
    sz = 1;
    while (sz < n)
      sz <<= 1;
    seg.assign(2 * sz, M1);
  }

  void set(int k, const Monoid &x) { seg[k + sz] = x; }

  void build() {
    for (int k = sz - 1; k > 0; k--) {
      seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
    }
  }

  void update(int k, const Monoid &x) {
    k += sz;
    seg[k] = x;
    while (k >>= 1) {
      seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
    }
  }

  Monoid query(int a, int b) {
    Monoid L = M1, R = M1;
    for (a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
      if (a & 1)
        L = f(L, seg[a++]);
      if (b & 1)
        R = f(seg[--b], R);
    }
    return f(L, R);
  }

  Monoid operator[](const int &k) const { return seg[k + sz]; }

  template <typename C>
  int find_subtree(int a, const C &check, Monoid &M, bool type) {
    while (a < sz) {
      Monoid nxt = type ? f(seg[2 * a + type], M) : f(M, seg[2 * a + type]);
      if (check(nxt))
        a = 2 * a + type;
      else
        M = nxt, a = 2 * a + 1 - type;
    }
    return a - sz;
  }

  template <typename C> int find_first(int a, const C &check) {
    Monoid L = M1;
    if (a <= 0) {
      if (check(f(L, seg[1])))
        return find_subtree(1, check, L, false);
      return -1;
    }
    int b = sz;
    for (a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
      if (a & 1) {
        Monoid nxt = f(L, seg[a]);
        if (check(nxt))
          return find_subtree(a, check, L, false);
        L = nxt;
        ++a;
      }
    }
    return -1;
  }

  template <typename C> int find_last(int b, const C &check) {
    Monoid R = M1;
    if (b >= sz) {
      if (check(f(seg[1], R)))
        return find_subtree(1, check, R, true);
      return -1;
    }
    int a = sz;
    for (b += sz; a < b; a >>= 1, b >>= 1) {
      if (b & 1) {
        Monoid nxt = f(seg[--b], R);
        if (check(nxt))
          return find_subtree(b, check, R, true);
        R = nxt;
      }
    }
    return -1;
  }
};

int N, K;
vector<int> P;

void input() {
  fast_io();
#ifdef __LOCAL
  fs::path p = __FILE__;
  fs::path input, output;
  input = output = p.parent_path();
  input += string("/input/") + string(p.stem()) + string(".txt");
  output += string("/output/") + string(p.stem()) + string(".txt");
  freopen(input.c_str(), "r", stdin);
  freopen(output.c_str(), "w", stdout);
#endif
  cin >> N >> K;
  P = fetch_vec<int>(N);
}

int TLEsolve() {
  if (K == 1) {
    cout << 1 << endl;
    return 0;
  }
  if (K == N) {
    cout << 1 << endl;
    return 0;
  }
  // 計算量を考慮せずに愚直にやる場合・・・
  map<vector<int>, int> cnt;
  vector<int> A;
  for (int i = 0; i <= N - K; i++) {
    A = P;
    sort(A.begin() + i, A.begin() + i + K);
    cnt[A]++;
    A.clear();
  }
  int ans;
  ans = cnt.size();
  cout << ans << endl;
  return ans;
}

map<int, vector<int>> G;
vector<bool> visited;

int dfs(int i) {
  // if(visited[i]) return 0;
  visited[i] = true;
  for (auto to : G[i]) {
    if (visited[to])
      continue;
    dfs(to);
  }
  return 0;
}

// RMQ だとO(NlogN)かかる
// スライド最小値だとO(N)
int RMQsolve() {
  if (K == 1) {
    cout << 1 << endl;
    return 0;
  }
  if (K == N) {
    cout << 1 << endl;
    return 0;
  }
  // deque<int> A;
  // しゃくとり法的にやる。
  // a1...a'i...a'i+k-1...an-1
  // a1...a'i+1...a'i+k...an-1
  // が同じ列 <==>
  // ai = min(ai,...,ai+k-1) and
  // ai+k > max(ai,...,ai+k-1)

  // セグ木使えばdequeは要らない。
  // for (int i = 0; i < K; i++)
  // {
  //     A.push_back(P[i]);
  // }

  [&]() {
    vector<pii> ZL;
    vector<int> sortedIdx;
    int r = 0;
    for (int i = 0; i < N - 1; i++) {
      if (P[i] < P[i + 1])
        r++;
      // else if(i==N-1) {r++;ZL.push_back(r);r=0;}
      else {
        r++;
        if (r >= K) {
          ZL.push_back({i, r});
        }
        r = 0;
      }
    }
    r++;
    if (r >= K)
      ZL.push_back({N - 1, r});
    DBG(ZL)
    for (auto z : ZL)
      while (z.second >= K) {
        sortedIdx.push_back(z.first - z.second + 1);
        z.second--;
      }
    ZL.clear();
    DBG(sortedIdx)
    for (auto i : sortedIdx)
      G[i] = sortedIdx;
    sortedIdx.clear();
  }();

  [&]() {
    SegmentTree<int> segMin(
        N, [](int a, int b) { return min(a, b); }, N + 10);
    SegmentTree<int> segMax(
        N, [](int a, int b) { return max(a, b); }, 0);
    for (int i = 0; i < N; i++) {
      segMin.update(i, P[i]);
      segMax.update(i, P[i]);
    }

    // max,minのクエリはセグ木を構築して高速化する。
    int mi = segMin.query(0, K);
    int ma = segMax.query(0, K);
    for (int i = 0; i < N - K; i++) {
      int out = P[i];
      int in = P[i + K];
      if (mi == out && ma < in) {
        G[i].push_back(i + 1);
        G[i + 1].push_back(i);
        ma = in;
        mi = segMin.query(i + 1, i + K + 1);
      }
      // else if(mi!=out && ma<in) {ma=in;}
      // else if(mi==out && ma>=in){mi=segMin.query(i+1,i+K+1);}
      // else if(mi!=out && ma>=in &&
      // ma==out){mi=min(mi,in);ma=segMax.query(i+1,i+K+1);} else if(mi!=out &&
      // ma>=in && ma!=out){mi=min(mi,in);}
      else {
        ma = segMax.query(i + 1, i + K + 1);
        mi = segMin.query(i + 1, i + K + 1);
      }
      // seg.query(a,b) : [a,b)に対する操作なのでbは対象外であることに注意
    }
  }();

  int ans = 0;
  visited.assign(N, false);
  for (int i = 0; i <= N - K; i++) {
    if (visited[i])
      continue;
    dfs(i);
    ans++;
  }
  cout << ans << endl;
  return ans;
}

int solve() {
  if (K == 1) {
    cout << 1 << endl;
    return 0;
  }
  if (K == N) {
    cout << 1 << endl;
    return 0;
  }
  // deque<int> A;
  // しゃくとり法的にやる。
  // a1...a'i...a'i+k-1...an-1
  // a1...a'i+1...a'i+k...an-1
  // が同じ列 <==>
  // ai = min(ai,...,ai+k-1) and
  // ai+k > max(ai,...,ai+k-1)

  // セグ木使えばdequeは要らない。
  // for (int i = 0; i < K; i++)
  // {
  //     A.push_back(P[i]);
  // }

  [&]() {
    vector<pii> ZL;
    vector<int> sortedIdx;
    int r = 0;
    for (int i = 0; i < N - 1; i++) {
      if (P[i] < P[i + 1])
        r++;
      // else if(i==N-1) {r++;ZL.push_back(r);r=0;}
      else {
        r++;
        if (r >= K) {
          ZL.push_back({i, r});
        }
        r = 0;
      }
    }
    r++;
    if (r >= K)
      ZL.push_back({N - 1, r});
    DBG(ZL)
    for (auto z : ZL)
      while (z.second >= K) {
        sortedIdx.push_back(z.first - z.second + 1);
        z.second--;
      }
    ZL.clear();
    DBG(sortedIdx)
    int j = sortedIdx[0];
    for (auto &i : sortedIdx) {
      G[i].push_back(j);
      G[j].push_back(i);
    }
    sortedIdx.clear();
  }();

  // スライド最小値
  deque<int> deq;
  vector<int> slideMin(N);
  for (int i = 0; i < N; i++) {
    while (!deq.empty() && P[deq.back()] >= P[i])
      deq.pop_back();
    deq.push_back(i);
    if (i - K + 1 >= 0) {
      slideMin[i - K + 1] = P[deq.front()];
      if (deq.front() == i - K + 1)
        deq.pop_front();
    }
  }
  DBG(slideMin)

  deq.clear();
  vector<int> slideMax(N);
  for (int i = 0; i < N; i++) {
    while (!deq.empty() && P[deq.back()] <= P[i])
      deq.pop_back();
    deq.push_back(i);
    if (i - K + 1 >= 0) {
      slideMax[i - K + 1] = P[deq.front()];
      if (deq.front() == i - K + 1)
        deq.pop_front();
    }
  }
  DBG(slideMax)
  deq.clear();

  int mi = slideMin[0];
  int ma = slideMax[0];
  int in, out;
  for (int i = 0; i < N - K; i++) {
    out = P[i];
    in = P[i + K];
    if (mi == out && ma < in) {
      G[i].push_back(i + 1);
      G[i + 1].push_back(i);
    }
    ma = slideMax[i + 1];
    mi = slideMin[i + 1];
  }

  int ans = 0;
  visited.assign(N, false);
  for (int i = 0; i <= N - K; i++) {
    if (visited[i])
      continue;
    dfs(i);
    ans++;
  }
  cout << ans << endl;
  return ans;
}

int main() {
  input();
  solve();
  return 0;
}


Fixed submission:
#include <bits/stdc++.h>

#ifdef __LOCAL
#define DBG(X) cout << #X << " = " << (X) << endl;
#define SAY(X) cout << (X) << endl;
#else
#define DBG(X)
#define SAY(X)
#endif

#ifdef __LOCAL
#include <filesystem>
namespace fs = std::filesystem;
#endif

using namespace std;

using ll = long long int;
using ull = unsigned long long int;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

int dx[] = {1, 0, -1, 0, 0};
int dy[] = {0, 1, 0, -1, 0};
const int INT_INF = (int)(2e9);
const ll LL_INF = (ll)(2e18);

inline void fast_io() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr);
};
template <typename T, typename S>
inline ostream &operator<<(ostream &os, const pair<T, S> p) {
  cout << "[" << p.first << ";" << p.second << "]";
  return os;
}
template <typename T>
inline ostream &operator<<(ostream &os, const vector<T> &v) {
  for (auto el : v)
    cout << el << " ";
  return os;
}
template <typename T> inline vector<T> fetch_vec(int sz) {
  vector<T> ret(sz);
  for (auto &elem : ret)
    cin >> elem;
  return ret;
}

template <typename Monoid> struct SegmentTree {
  using F = function<Monoid(Monoid, Monoid)>;

  int sz;
  vector<Monoid> seg;

  const F f;
  const Monoid M1;

  SegmentTree(int n, const F f, const Monoid &M1) : f(f), M1(M1) {
    sz = 1;
    while (sz < n)
      sz <<= 1;
    seg.assign(2 * sz, M1);
  }

  void set(int k, const Monoid &x) { seg[k + sz] = x; }

  void build() {
    for (int k = sz - 1; k > 0; k--) {
      seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
    }
  }

  void update(int k, const Monoid &x) {
    k += sz;
    seg[k] = x;
    while (k >>= 1) {
      seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
    }
  }

  Monoid query(int a, int b) {
    Monoid L = M1, R = M1;
    for (a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
      if (a & 1)
        L = f(L, seg[a++]);
      if (b & 1)
        R = f(seg[--b], R);
    }
    return f(L, R);
  }

  Monoid operator[](const int &k) const { return seg[k + sz]; }

  template <typename C>
  int find_subtree(int a, const C &check, Monoid &M, bool type) {
    while (a < sz) {
      Monoid nxt = type ? f(seg[2 * a + type], M) : f(M, seg[2 * a + type]);
      if (check(nxt))
        a = 2 * a + type;
      else
        M = nxt, a = 2 * a + 1 - type;
    }
    return a - sz;
  }

  template <typename C> int find_first(int a, const C &check) {
    Monoid L = M1;
    if (a <= 0) {
      if (check(f(L, seg[1])))
        return find_subtree(1, check, L, false);
      return -1;
    }
    int b = sz;
    for (a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
      if (a & 1) {
        Monoid nxt = f(L, seg[a]);
        if (check(nxt))
          return find_subtree(a, check, L, false);
        L = nxt;
        ++a;
      }
    }
    return -1;
  }

  template <typename C> int find_last(int b, const C &check) {
    Monoid R = M1;
    if (b >= sz) {
      if (check(f(seg[1], R)))
        return find_subtree(1, check, R, true);
      return -1;
    }
    int a = sz;
    for (b += sz; a < b; a >>= 1, b >>= 1) {
      if (b & 1) {
        Monoid nxt = f(seg[--b], R);
        if (check(nxt))
          return find_subtree(b, check, R, true);
        R = nxt;
      }
    }
    return -1;
  }
};

int N, K;
vector<int> P;

void input() {
  fast_io();
#ifdef __LOCAL
  fs::path p = __FILE__;
  fs::path input, output;
  input = output = p.parent_path();
  input += string("/input/") + string(p.stem()) + string(".txt");
  output += string("/output/") + string(p.stem()) + string(".txt");
  freopen(input.c_str(), "r", stdin);
  freopen(output.c_str(), "w", stdout);
#endif
  cin >> N >> K;
  P = fetch_vec<int>(N);
}

int TLEsolve() {
  if (K == 1) {
    cout << 1 << endl;
    return 0;
  }
  if (K == N) {
    cout << 1 << endl;
    return 0;
  }
  // 計算量を考慮せずに愚直にやる場合・・・
  map<vector<int>, int> cnt;
  vector<int> A;
  for (int i = 0; i <= N - K; i++) {
    A = P;
    sort(A.begin() + i, A.begin() + i + K);
    cnt[A]++;
    A.clear();
  }
  int ans;
  ans = cnt.size();
  cout << ans << endl;
  return ans;
}

map<int, vector<int>> G;
vector<bool> visited;

int dfs(int i) {
  // if(visited[i]) return 0;
  visited[i] = true;
  for (auto to : G[i]) {
    if (visited[to])
      continue;
    dfs(to);
  }
  return 0;
}

// RMQ だとO(NlogN)かかる
// スライド最小値だとO(N)
int RMQsolve() {
  if (K == 1) {
    cout << 1 << endl;
    return 0;
  }
  if (K == N) {
    cout << 1 << endl;
    return 0;
  }
  // deque<int> A;
  // しゃくとり法的にやる。
  // a1...a'i...a'i+k-1...an-1
  // a1...a'i+1...a'i+k...an-1
  // が同じ列 <==>
  // ai = min(ai,...,ai+k-1) and
  // ai+k > max(ai,...,ai+k-1)

  // セグ木使えばdequeは要らない。
  // for (int i = 0; i < K; i++)
  // {
  //     A.push_back(P[i]);
  // }

  [&]() {
    vector<pii> ZL;
    vector<int> sortedIdx;
    int r = 0;
    for (int i = 0; i < N - 1; i++) {
      if (P[i] < P[i + 1])
        r++;
      // else if(i==N-1) {r++;ZL.push_back(r);r=0;}
      else {
        r++;
        if (r >= K) {
          ZL.push_back({i, r});
        }
        r = 0;
      }
    }
    r++;
    if (r >= K)
      ZL.push_back({N - 1, r});
    DBG(ZL)
    for (auto z : ZL)
      while (z.second >= K) {
        sortedIdx.push_back(z.first - z.second + 1);
        z.second--;
      }
    ZL.clear();
    DBG(sortedIdx)
    for (auto i : sortedIdx)
      G[i] = sortedIdx;
    sortedIdx.clear();
  }();

  [&]() {
    SegmentTree<int> segMin(
        N, [](int a, int b) { return min(a, b); }, N + 10);
    SegmentTree<int> segMax(
        N, [](int a, int b) { return max(a, b); }, 0);
    for (int i = 0; i < N; i++) {
      segMin.update(i, P[i]);
      segMax.update(i, P[i]);
    }

    // max,minのクエリはセグ木を構築して高速化する。
    int mi = segMin.query(0, K);
    int ma = segMax.query(0, K);
    for (int i = 0; i < N - K; i++) {
      int out = P[i];
      int in = P[i + K];
      if (mi == out && ma < in) {
        G[i].push_back(i + 1);
        G[i + 1].push_back(i);
        ma = in;
        mi = segMin.query(i + 1, i + K + 1);
      }
      // else if(mi!=out && ma<in) {ma=in;}
      // else if(mi==out && ma>=in){mi=segMin.query(i+1,i+K+1);}
      // else if(mi!=out && ma>=in &&
      // ma==out){mi=min(mi,in);ma=segMax.query(i+1,i+K+1);} else if(mi!=out &&
      // ma>=in && ma!=out){mi=min(mi,in);}
      else {
        ma = segMax.query(i + 1, i + K + 1);
        mi = segMin.query(i + 1, i + K + 1);
      }
      // seg.query(a,b) : [a,b)に対する操作なのでbは対象外であることに注意
    }
  }();

  int ans = 0;
  visited.assign(N, false);
  for (int i = 0; i <= N - K; i++) {
    if (visited[i])
      continue;
    dfs(i);
    ans++;
  }
  cout << ans << endl;
  return ans;
}

int solve() {
  if (K == 1) {
    cout << 1 << endl;
    return 0;
  }
  if (K == N) {
    cout << 1 << endl;
    return 0;
  }
  // deque<int> A;
  // しゃくとり法的にやる。
  // a1...a'i...a'i+k-1...an-1
  // a1...a'i+1...a'i+k...an-1
  // が同じ列 <==>
  // ai = min(ai,...,ai+k-1) and
  // ai+k > max(ai,...,ai+k-1)

  // セグ木使えばdequeは要らない。
  // for (int i = 0; i < K; i++)
  // {
  //     A.push_back(P[i]);
  // }

  [&]() {
    vector<pii> ZL;
    vector<int> sortedIdx;
    int r = 0;
    for (int i = 0; i < N - 1; i++) {
      if (P[i] < P[i + 1])
        r++;
      // else if(i==N-1) {r++;ZL.push_back(r);r=0;}
      else {
        r++;
        if (r >= K) {
          ZL.push_back({i, r});
        }
        r = 0;
      }
    }
    r++;
    if (r >= K)
      ZL.push_back({N - 1, r});
    DBG(ZL)
    for (auto z : ZL)
      while (z.second >= K) {
        sortedIdx.push_back(z.first - z.second + 1);
        z.second--;
      }
    ZL.clear();
    DBG(sortedIdx)
    if (sortedIdx.size() > 0) {
      int j = sortedIdx[0];
      for (auto &i : sortedIdx) {
        G[i].push_back(j);
        G[j].push_back(i);
      }
      sortedIdx.clear();
    }
  }();

  // スライド最小値
  deque<int> deq;
  vector<int> slideMin(N);
  for (int i = 0; i < N; i++) {
    while (!deq.empty() && P[deq.back()] >= P[i])
      deq.pop_back();
    deq.push_back(i);
    if (i - K + 1 >= 0) {
      slideMin[i - K + 1] = P[deq.front()];
      if (deq.front() == i - K + 1)
        deq.pop_front();
    }
  }
  DBG(slideMin)

  deq.clear();
  vector<int> slideMax(N);
  for (int i = 0; i < N; i++) {
    while (!deq.empty() && P[deq.back()] <= P[i])
      deq.pop_back();
    deq.push_back(i);
    if (i - K + 1 >= 0) {
      slideMax[i - K + 1] = P[deq.front()];
      if (deq.front() == i - K + 1)
        deq.pop_front();
    }
  }
  DBG(slideMax)
  deq.clear();

  int mi = slideMin[0];
  int ma = slideMax[0];
  int in, out;
  for (int i = 0; i < N - K; i++) {
    out = P[i];
    in = P[i + K];
    if (mi == out && ma < in) {
      G[i].push_back(i + 1);
      G[i + 1].push_back(i);
    }
    ma = slideMax[i + 1];
    mi = slideMin[i + 1];
  }

  int ans = 0;
  visited.assign(N, false);
  for (int i = 0; i <= N - K; i++) {
    if (visited[i])
      continue;
    dfs(i);
    ans++;
  }
  cout << ans << endl;
  return ans;
}

int main() {
  input();
  solve();
  return 0;
}