Stunning Garbanzo
open main menu
Part of series: PS

5012 BOJ

/ 2 min read

문제

접근

세그먼트 트리를 이용해 해결하였다.

세그먼트 트리를 이용한 inversion 찾기를 두번 수행하면 된다. 세 원소가 중 가운데 원소를 기준으로 왼쪽의 inversion과 오른쪽의 inversion을 찾으면 된다. 이후 해당 inversion들의 곱을 전부 더해주면 된다.

코드

#include <algorithm>
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef const ll cll;

cll N = 1e5;
ll n, inputs[N] = {}, segs[N * 10] = {}, invs[2][N] = {{}};

ll insert(ll node, ll idx0, ll idx1, cll num) {
  if (num < idx0 || num > idx1) {
    return segs[node];
  } else if (idx0 == idx1) {
    return ++segs[node];
  }

  ll mid = (idx0 + idx1) / 2;
  return segs[node] = insert(node * 2, idx0, mid, num) +
                      insert(node * 2 + 1, mid + 1, idx1, num);
}

ll search0(ll node, ll idx0, ll idx1, cll num, bool isGreat) {
  if (isGreat) {
    if (idx1 <= num) {
      return 0;
    } else if (idx0 > num) {
      return segs[node];
    }
  } else {
    if (idx0 >= num) {
      return 0;
    } else if (idx1 < num) {
      return segs[node];
    }
  }

  ll mid = (idx0 + idx1) / 2;
  return search0(node * 2, idx0, mid, num, isGreat) +
         search0(node * 2 + 1, mid + 1, idx1, num, isGreat);
}

int main(void) {
  ios::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);

  cin >> n;
  for (ll i = 0; i < n; ++i) {
    cin >> inputs[i];
    invs[0][i] = search0(1, 1, n, inputs[i], true);
    insert(1, 1, n, inputs[i]);
  }
  memset(segs, 0, sizeof(segs));
  for (ll i = n - 1; i >= 0; --i) {
    invs[1][i] = search0(1, 1, n, inputs[i], false);
    insert(1, 1, n, inputs[i]);
  }

  ll result = 0;
  for (ll i = 0; i < n; ++i) {
    result += invs[0][i] * invs[1][i];
  }

  cout << result << "\n";

  return 0;
}