https://www.acmicpc.net/problem/7469

 

7469번: K번째 수

문제 현정이는 자료 구조 프로젝트를 하고 있다. 다른 학생들은 프로젝트 주제로 스택, 큐와 같은 기본 자료 구조를 구현하는 주제를 선택했다. 하지만, 현정이는 새로운 자료 구조를 만들었다. 현정이가 만든 자료구조는 배열을 응용하는 것이다. 배열 a[1...n]에는 서로 다른 수가 n개 저장되어 있다. 현정이는 여기에 Q(i,j,k)라는 함수를 구현해 모두를 놀라게 할 것이다. Q(i,j,k): 배열 a[i...j]를 정렬했을 때, k번째 수를 리턴하는 함

www.acmicpc.net


트리의 노드는 하위 노드들의 값의 정렬된 배열형태로 저장되어야 하고.

파라매트릭 서치를 이용해서 값을 찾아내야 시간초과에 걸리지 않는다.

파라매트릭 서치의 아이디어는 생각해내지 못해서 구글링을통해 겨우 알았다..ㅠ


#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define MAX_N 100001
vector<int> tree[MAX_N*4]; // 트리는 vector 형태로 정렬되서 자기 하위 노드들의 값이 저장되어 있음.

void update_tree(int now, int target, int start, int end, int value) {
     if (target > end || target < start) return;
     if (start == end) {
          tree[now].push_back(value);
          return;
     }
     // merge sort 를 사용한 init 을 사용하면 더 좋겠지만, 큰차이 없으므로 그냥 main 함수에서 for문으로 sort해주었음.
     tree[now].push_back(value);
     int mid = (start + end) / 2;
     update_tree(now * 2, target, start, mid, value);
     update_tree(now * 2 + 1, target, mid + 1, end, value);
}

// index를 리턴해준다
int query(int now, int left, int right, int start, int end,int k) {
     if (left > end || right < start)  {
          return 0;
     }
     if (left <= start && end <= right) {
          return upper_bound(tree[now].begin(), tree[now].end(), k) - tree[now].begin();
     }
     int mid = (start + end) / 2;
     return query(now * 2, left, right, start, mid, k) + query(now * 2 + 1, left, right, mid + 1, end, k);
}

int main() {
     ios::sync_with_stdio(false);
     cin.tie(0);
     cout.tie(0);
     int n, Q;
     cin >> n >> Q;
     for (int i = 0; i < n; i++) {
          int data; cin >> data;
          update_tree(1, i, 0, n - 1, data);
     }

     for (int i = 0; i <= 4 * n; i++) {
          sort(tree[i].begin(), tree[i].end());
     }

     for (int i = 0; i < Q; i++) {
          int s, e, x;
          cin >> s >> e >> x;
          // 문제에서 나타나있는 최대범위를 이용해서 파라매트릭 서치의 최소와 최댓값을 정해준다
          int MIN = -1e9, MAX = 1e9;
          while (MIN <= MAX) {
               int MID = (MIN + MAX) / 2;
               // s ~ e 값사이의 MID 값이 k번쨰 숫자일 경우
               // k < x : mid값을 높여 줘야 k가 x이상이 나올 수 있다.
               // k > x : mid값을 낮춰 줘야 k가 x이하가 나올 수 있다.
               int k = query(1, s-1, e-1, 0, n-1, MID);
               if (k < x) MIN = MID + 1;
               else MAX = MID - 1;
          }
          // else 구문에서 " k == x " 인경우에 계속 숫자를 낮춰 줬기 때문에, MIN 값이 곧 답이 된다.
          cout << MIN << "\n";
     }
}

겨우겨우 풀어냈고, 다른 분들의 풀이를 보고 다른 방법도 익혀봐야 겠다.

 

'알고리즘 > [C++]BOJ' 카테고리의 다른 글

[백준] 5676_음주 코딩 (C++)  (0) 2019.09.30
[백준]1275_커피숍2(C++)  (0) 2019.09.29
[백준]3653_영화 수집(C++)  (0) 2019.09.29

+ Recent posts