https://www.acmicpc.net/problem/2336
2336번: 굉장한 학생
문제 N명의 학생이 참여하여 세 번의 시험을 치렀다. N명의 학생들은 세 번의 시험에 모두 응시하였다. 조교는 각각의 시험에서 같은 등수의 학생이 한 명도 없도록 성적을 매겼다. A라는 학생이 B라는 학생보다 세 번의 시험에서 모두 성적이 좋다면, A가 B보다 '대단하다'고 한다. 또, C라는 학생보다 '대단한' 학생이 한 명도 없으면, C를 '굉장하다'고 한다. 세 번의 시험에서 각 학생의 성적이 주어졌을 때, '굉장한' 학생의 수를 구하는 프로그램을
www.acmicpc.net
정렬과 세그먼트트리를 이용하여 해결 할 수 있다.

1번 학생 : 0등 1등 7등
2번 학생 : 1등 4등 4등
3번 학생 : 2등 2등 0등
4번 학생 : 3등 7등 1등
5번 학생 : 4등 9등 3등
6번 학생 : 5등 6등 2등
7번 학생 : 6등 0등 6등
8번 학생 : 7등 5등 8등
9번 학생 : 8등 8등 9등
10번 학생 : 9등 3등 5등
로 정렬한뒤에 1번학생 ~ 10번 학생을 처리 하게 되는데,
1번학생은 반드시 굉장한 학생이 될 것이다.
2번학생은 오직 1번학생보다 하나만이라도 높다면 굉장한 학생이 될 것이다.
3번학생은 1,2번학생보다 등수가 모두 높다면 높다면 굉장한 학생이 될 것이다.
...
N번 학생은 N-1학생보다 등수가 다 높다면 굉장한 학생이 될 것이다.
< 1번 학생 >
1번째 리프노드 7로 update
< 2번 학생 >
0~3번 중 최솟값이 현재 7이므로 굉장한 학생이다
4번쨰 리프노드 4로 update
< 3번 학생 >
0~1번중 최솟값이 현재 7이므로 굉장한 학생이다
2번째 리프노드 0으로 update( 이학생 때문에 뒤의 학생들은 대부분 굉장한 학생이 아니게 된다 )
< 4번 학생 >
0~5번중 최솟값이 0이므로 이학생은 굉장한 학생이 아니다.
7번째 리프노드를 1로 update
.... 반복 ....
#include <iostream> #include <algorithm> using namespace std; #define MAX_N 500000 class Info { public : int x, y, z; Info() {} Info(int x, int y, int z) { this->x = x; this->y = y; this->z = z; } bool operator < (const Info & b) const { return this->x < b.x; } }; Info arr[MAX_N]; int tree[MAX_N * 4]; void init_tree(int now, int start, int end) { if (start > end) return; if (start == end) { tree[now] = 1e9; return; } int mid = (start + end) / 2; tree[now] = 1e9; init_tree(now * 2, start, mid); init_tree(now * 2 + 1, mid + 1, end); } int update_tree(int now, int target, int start, int end, int value) { if (target > end || target < start) return tree[now]; if (start == end) { return tree[now] = value; } int mid = (start + end) / 2; tree[now] = min( update_tree(now * 2, target, start, mid, value), update_tree(now * 2 + 1, target, mid + 1, end, value) ); return tree[now]; } int getMin(int now, int left, int right, int start, int end) { if (left > end || right < start) return 1e9; if (left <= start && end <= right) return tree[now]; int mid = (start + end) / 2; return min( getMin(now * 2 , left, right, start, mid), getMin(now * 2 + 1, left, right, mid + 1, end) ); } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int N; cin >> N; for (int i = 0; i < N; i++) { int t; cin >> t; t--; arr[t].x = i; } for (int i = 0; i < N; i++) { int t; cin >> t; t--; arr[t].y = i; } for (int i = 0; i < N; i++) { int t; cin >> t; t--; arr[t].z = i; } sort(arr, arr + N); init_tree(1,0,N-1); int ans = 0; for (int i = 0; i < N; i++) { int y = arr[i].y; int z = arr[i].z; if (getMin(1, 0, y, 0, N - 1) > z) ans++; update_tree(1, y, 0, N - 1, z); } cout << ans << "\n"; }
나한텐 너무 어려운 문제였지만, x,y,z를 묶어서 sort뒤의
출력물을 보고나서 쉽게 접근 할 수 있었다.
'알고리즘 > [C++]BOJ' 카테고리의 다른 글
[백준] 2269_수들의합 (C++) (0) | 2019.10.01 |
---|---|
[백준] 3392_화성지도 (C++) (0) | 2019.09.30 |
[백준] 5676_음주 코딩 (C++) (0) | 2019.09.30 |