Problem p02689 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <algorithm>
#include <iostream>
#include <limits.h>
#include <math.h>
#include <queue>
#include <random>
#include <set>
#include <stdio.h>
#include <string>
#include <vector>

#define lli long long int
#define MOD 1000000007

using namespace std;

long long int modpow(long long int a, long long int n) {
  if (n == 0)
    return 1;
  if (n == 1)
    return (a % MOD);

  long long int hanbun = n / 2;
  long long int amari = n % 2;

  long long int ans = (a * a) % MOD;
  ans = modpow(ans, hanbun);

  if (amari == 1)
    ans *= a;

  ans %= MOD;

  return ans;
}

long long int gcd(long long int a, long long int b) {
  if (a < b) {
    long long int tmp = a;
    a = b;
    b = tmp;
  }

  long long int amari = a % b;

  if (amari == 0)
    return b;

  return gcd(b, amari);
}

long long int lcm(long long int a, long long int b) {
  long long int ans = (a * b) % MOD;
  long long int wari = modpow(gcd(a, b), MOD - 2);
  ans = (ans * wari) % MOD;
  return ans;
}

long long int factElement[10000] = {0};

long long int factrial(int n) {

  if (factElement[n] != 0)
    return factElement[n];

  if (n == 0) {
    factElement[0] = 1;
    return factElement[n];
  }

  long long int ans = n * factrial(n - 1);
  factElement[n] = ans;
  return factElement[n];
}

struct SegmentTree {
private:
  int n;
  vector<long long int> node;
  int TANNI;

  long long int Func(long long int a, long long int b) { return min(a, b); }

public:
  // 元配列ｖをセグメント木で表現する。
  SegmentTree(vector<long long int> v, long long int tanni) {
    // 最下段のノード数は元配列のサイズ以上になる最小の2冪→これをｎとおく。
    // セグメント木全体で必要なノード数は2n-1個である。
    int sz = v.size();
    n = 1;
    while (n < sz)
      n *= 2;

    TANNI = tanni;
    node.resize(2 * n - 1, TANNI);

    // 最下段に値を入れた後に、下の段から順番に値を入れる。
    // 値を入れるには、自分の子の２値を参照すればよい。
    for (int i = 0; i < sz; i++)
      node[i + n - 1] = v[i];
    for (int i = n - 2; i >= 0; i--)
      node[i] = Func(node[2 * i + 1], node[2 * i + 2]);
  }

  void update(long long int x, long long int val) {
    // 最下段のノードにアクセスする。
    x += (n - 1);

    // 最下段のノードを更新したら、あとは親に上って更新していく。
    node[x] = val;

    while (x > 0) {
      x = (x - 1) / 2;
      node[x] = Func(node[2 * x + 1], node[2 * x + 2]);
    }
  }

  long long int getVal(int x) {
    x += (n - 1);
    return node[x];
  }

  long long int getAns(int a, int b, int k = 0, int l = 0, int r = -1) {
    // 最初に呼び出された時の区間は[0,n)
    if (r < 0)
      r = n;

    // 要求区間と対象区間が交わらない→単位元を返す。
    if (r <= a || b <= l)
      return TANNI;

    // 要求区間が対象区間を完全に被覆する→対象区間を答えの計算に使う。
    if (a <= l && r <= b)
      return node[k];

    // 要求区間が対象区間の一部を被覆→子をよびだす。
    // 左の子をvl、右の子をvrとしている。
    // 新しい対象区間は現在の対象区間を半分に割ったもの。
    int vl = getAns(a, b, 2 * k + 1, l, (l + r) / 2);
    int vr = getAns(a, b, 2 * k + 2, (l + r) / 2, r);
    return Func(vl, vr);
  }
};

int main() {

  int n, m;
  cin >> n >> m;

  vector<int> h(n);
  for (auto &i : h)
    cin >> i;

  vector<int> a(m);
  vector<int> b(m);
  for (int i = 0; i < m; i++) {
    cin >> a[i];
    cin >> b[i];
  }

  vector<bool> good(n, true);
  int ans = 0;

  for (int i = 0; i < m; i++) {
    if (h[a[i] - 1] < h[b[i] - 1]) {
      good[a[i] - 1] = false;
    } else if (h[a[i] - 1] > h[b[i] - 1]) {
      good[b[i] - 1] = false;
    } else {
      good[a[i] - 1] = false;
      good[b[i] - 1] = false;
    }
  }

  for (int i = 0; i < n; i++) {
    if (good[i])
      ans++;
  }

  cout << ans << endl;

  return 0;
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <iostream>
#include <limits.h>
#include <math.h>
#include <queue>
#include <random>
#include <set>
#include <stdio.h>
#include <string>
#include <vector>

#define lli long long int
#define MOD 1000000007

using namespace std;

long long int modpow(long long int a, long long int n) {
  if (n == 0)
    return 1;
  if (n == 1)
    return (a % MOD);

  long long int hanbun = n / 2;
  long long int amari = n % 2;

  long long int ans = (a * a) % MOD;
  ans = modpow(ans, hanbun);

  if (amari == 1)
    ans *= a;

  ans %= MOD;

  return ans;
}

long long int gcd(long long int a, long long int b) {
  if (a < b) {
    long long int tmp = a;
    a = b;
    b = tmp;
  }

  long long int amari = a % b;

  if (amari == 0)
    return b;

  return gcd(b, amari);
}

long long int lcm(long long int a, long long int b) {
  long long int ans = (a * b) % MOD;
  long long int wari = modpow(gcd(a, b), MOD - 2);
  ans = (ans * wari) % MOD;
  return ans;
}

long long int factElement[10000] = {0};

long long int factrial(int n) {

  if (factElement[n] != 0)
    return factElement[n];

  if (n == 0) {
    factElement[0] = 1;
    return factElement[n];
  }

  long long int ans = n * factrial(n - 1);
  factElement[n] = ans;
  return factElement[n];
}

struct SegmentTree {
private:
  int n;
  vector<long long int> node;
  int TANNI;

  long long int Func(long long int a, long long int b) { return min(a, b); }

public:
  // 元配列ｖをセグメント木で表現する。
  SegmentTree(vector<long long int> v, long long int tanni) {
    // 最下段のノード数は元配列のサイズ以上になる最小の2冪→これをｎとおく。
    // セグメント木全体で必要なノード数は2n-1個である。
    int sz = v.size();
    n = 1;
    while (n < sz)
      n *= 2;

    TANNI = tanni;
    node.resize(2 * n - 1, TANNI);

    // 最下段に値を入れた後に、下の段から順番に値を入れる。
    // 値を入れるには、自分の子の２値を参照すればよい。
    for (int i = 0; i < sz; i++)
      node[i + n - 1] = v[i];
    for (int i = n - 2; i >= 0; i--)
      node[i] = Func(node[2 * i + 1], node[2 * i + 2]);
  }

  void update(long long int x, long long int val) {
    // 最下段のノードにアクセスする。
    x += (n - 1);

    // 最下段のノードを更新したら、あとは親に上って更新していく。
    node[x] = val;

    while (x > 0) {
      x = (x - 1) / 2;
      node[x] = Func(node[2 * x + 1], node[2 * x + 2]);
    }
  }

  long long int getVal(int x) {
    x += (n - 1);
    return node[x];
  }

  long long int getAns(int a, int b, int k = 0, int l = 0, int r = -1) {
    // 最初に呼び出された時の区間は[0,n)
    if (r < 0)
      r = n;

    // 要求区間と対象区間が交わらない→単位元を返す。
    if (r <= a || b <= l)
      return TANNI;

    // 要求区間が対象区間を完全に被覆する→対象区間を答えの計算に使う。
    if (a <= l && r <= b)
      return node[k];

    // 要求区間が対象区間の一部を被覆→子をよびだす。
    // 左の子をvl、右の子をvrとしている。
    // 新しい対象区間は現在の対象区間を半分に割ったもの。
    int vl = getAns(a, b, 2 * k + 1, l, (l + r) / 2);
    int vr = getAns(a, b, 2 * k + 2, (l + r) / 2, r);
    return Func(vl, vr);
  }
};

int main() {

  int n, m;
  cin >> n >> m;

  vector<int> h(n);
  for (auto &i : h)
    cin >> i;

  vector<int> a(m);
  vector<int> b(m);
  for (int i = 0; i < m; i++) {
    cin >> a[i];
    cin >> b[i];
  }

  vector<bool> dame(n, false);
  int ans = 0;

  for (int i = 0; i < n; i++) {
    if (dame[i] == true)
      continue;

    for (int j = 0; j < m; j++) {
      if (a[j] == i + 1) {
        if (h[i] <= h[b[j] - 1]) {
          dame[i] = true;
        } else {
          dame[b[j] - 1] = true;
        }

      } else if (b[j] == i + 1) {
        if (h[i] <= h[a[j] - 1]) {
          dame[i] = true;
        } else {
          dame[a[j] - 1] = true;
        }
      }

      if (dame[i])
        break;
    }

    if (dame[i] == false)
      ans++;
  }

  cout << ans << endl;

  return 0;
}