Problem Solving/BOJ

[백준 2336번] [세그먼트 트리 / 스위핑] 굉장한 학생

  • -
728x90
반응형

상당히 재밌는 문제이다.

문제를 요약하자면, 3개의 시험에 대해서 모두 다 우월한 학생이 있는지를 판단하는 것이 굉장히 중요하다.

 

일단 첫번째 시험을 기준으로 오름차순으로 정렬을 한다.

정렬된 결과에서 앞에 위치하는 학생은 적어도 첫번째 시험을 더 잘 본 것이므로, 해당 학생보다 뒤에 위치하는 학생은 굉장한 학생한 학생을 판단하는 과정에서 고려하지 않아도 된다. 따라서 첫 시험을 기준으로 정렬을 한 뒤, 해당 학생의 앞에 있는 학생 중 2, 3번째 시험을 모두 더 잘 본 학생이 없다면 해당 학생은 굉장한 학생이라고 판단해주면 된다.

 

따라서, 이 문제를 풀기 위해서 실질적으로 해결해야하는 부분은

"해당 학생의 앞에 있는 학생 중 2, 3번째 시험을 모두 더 잘 본 사람이 있는지 여부"이다.

1번째 시험을 고려하지 말고, 2, 3번째 시험만 고려하여 상황을 단순화시켜보자.

그렇게 되면, 2번째 시험이 i등인 학생이 굉장한 학생임을 판단하기 위해서는 2번째 시험이 1등 ~ i - 1등까지의 학생들의 세번째 시험의 최솟값보다 현재 2번째 시험이 i등인 학생의 3번째 시험의 등수보다 더 큰 것이 있는지를 판단해주면 된다. 만약 더 작은 것이 존재하면 현재 학생은 굉장한 학생이 아니고, 그렇지 않으면 굉장한 학생이 된다. 잘 보면, 1 ~ i - 1등까지의 구간의 최솟값을 지속적으로 구하고 있는 상황이 반복되고 있음을 파악할 수 있고 따라서 Min segment tree를 활용하여, 해당 구간의 최솟값을 구하여 굉장한 학생 여부를 판단할 수 있게 된다.

 

첫번째 시험까지 고려하기 위해서는 어떻게 하면 될까?

그렇게 하기 위해서는 모든 노드를 INF로 초기화해주고, 첫번째 시험을 잘 본 순서대로 해당 학생이 굉장한 학생인지를 판단해주고, segment tree를 update해주는 과정을 거치면 된다.(세그먼트 트리에는 3번째 등수에 대한 정보를 저장하게 된다.). 먼저 처리한 것들에 대해서만 INF값을 가지지 않으므로,구간 1 ~ i - 1등까지의 구간에 대한 정보값을 확인하는 것과 해당 학생보다 1, 2번째 시험을 모두 잘 본 학생들의 구간을 확인하는 것은 동치다.

#include <bits/stdc++.h> #define fastio cin.tie(0)->sync_with_stdio(0) using namespace std; using ll = long long; using pii = pair<int, int>; using tiii = tuple<int, int, int>; int move_x[4] = {-1, 1, 0, 0}; int move_y[4] = {0, 0, -1, 1}; class ptr{ public: int x, y, z; }; bool cmp(ptr &v1, ptr &v2){ return v1.x < v2.x; } const int sz = 500010; ptr arr[sz]; int tree[4 * sz]; const int INF = 2000000000; int update(int node, int start, int end, int idx, int value){ if(idx < start || end < idx) return tree[node]; if(start == end) return tree[node] = value; int mid = (start + end) >> 1; return tree[node] = min( update(node * 2, start, mid, idx, value), update(node * 2 + 1, mid + 1, end, idx, value) ); } int query(int node, int start, int end, int left, int right){ if(right < start || end < left) return INF; if(left <= start && end <= right) return tree[node]; int mid = (start + end) >> 1; return min( query(node * 2, start, mid, left, right), query(node * 2 + 1, mid + 1, end, left, right) ); } int main() { fastio; int n; cin >> n; for(int i = 1; i <= n; i++){ int t; cin >> t; arr[t].x = i; } for(int i = 1; i <= n; i++){ int t; cin >> t; arr[t].y = i; } for(int i = 1; i <= n; i++){ int t; cin >> t; arr[t].z = i; } sort(arr + 1, arr + n + 1, cmp); fill(&tree[0], &tree[4 * sz], INF); int ret = 0; for(int i = 1; i <= n; i++){ if(query(1, 1, n, 1, arr[i].y) > arr[i].z) ret++; update(1, 1, n, arr[i].y, arr[i].z); } cout << ret << "\n"; }
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.