반응형
https://www.acmicpc.net/problem/3653
3653번: 영화 수집
각 테스트 케이스에 대해서 한 줄에 m개의 정수를 출력해야 한다. i번째 출력하는 수는 i번째로 영화를 볼 때 그 영화의 위에 있었던 DVD의 개수이다. 상근이는 매번 영화를 볼 때마다 본 영화 DVD
www.acmicpc.net
[ 문제풀이 ]
이 문제를 풀기 전에 다음 글을 먼저 읽고 오시는 것을 추천드립니다!
https://rudalsd.tistory.com/51?category=1073064
[ 자료구조 ] 세그먼트 트리 (Segment Tree)
1. 세그먼트 트리 (Segment Tree) 먼저, 세그먼트 트리가 무엇인지 알아봅시다! 세그먼트 트리는 구간 합을 저장하기 위한 트리입니다. 예를 들어 size가 5인 배열이 있다고 생각해봅시다. int arr [5] = {1
rudalsd.tistory.com
1. pos배열을 이용하여 1 ~ n까지의 DVD가 몇 번 idx에 있는지 저장합니다.
2. n + m개의 리프가 있는 세그먼트 트리를 만들어서 1 ~ n개까지의 리프를 채웁니다.
3. 원하는 DVD의 idx를 0으로 업데이트합니다.
4. idx부터 n+i까지 dvd의 개수를 구한 후 출력합니다.
5. n+i 리프를 1로 업데이트합니다.
6. 원하는 DVD의 idx를 n+i로 갱신해줍니다.
7. 위의 과정을 반복합니다.
[ 소스 코드 ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | #include<iostream> #include<vector> #include<cmath> using namespace std; int n, m; vector<int> segmentTree; int pos[100001]; int makeTree(int node, int start, int end) //트리 만들기 { if (start == end) { if (start <= n) { return segmentTree[node] = 1; } else { return 0; } } int mid = (start + end) / 2; int left = makeTree(node * 2, start, mid); int right = makeTree(node * 2 + 1, mid + 1, end); return segmentTree[node] = left + right; } void get(int node, int start, int end, int idx) //dvd 빼기 { if (idx < start || idx > end) { return; } else { segmentTree[node]--; } if (start == end) return; int mid = (start + end) / 2; get(node * 2, start, mid, idx); get(node * 2 + 1, mid + 1, end, idx); } void put(int node, int start, int end, int idx) //dvd 넣기 { if (idx < start || idx > end) { return; } else { segmentTree[node]++; } if (start == end) return; int mid = (start + end) / 2; put(node * 2, start, mid, idx); put(node * 2 + 1, mid + 1, end, idx); } int sum(int node, int start, int end, int sidx, int eidx) //합 구하기 { if (sidx > end || eidx < start) return 0; if (sidx <= start && end <= eidx) return segmentTree[node]; int mid = (start + end) / 2; int left = sum(node * 2, start, mid, sidx, eidx); int right = sum(node * 2 + 1, mid + 1, end, sidx, eidx); return left + right; } int main() { int T; scanf("%d", &T); for (int t = 0; t < T; t++) { scanf("%d %d", &n, &m); for (int i = 1; i <= n; i++) { pos[i] = n - i + 1; } int size = (1 << (int)ceil(log2(n+m)) + 1); segmentTree.clear(); segmentTree.resize(size); makeTree(1,1,n+m); for (int i = 1; i <= m; i++) { int num; scanf("%d", &num); get(1, 1, n + m, pos[num]); printf("%d ", sum(1, 1, n + m, pos[num], n + i - 1)); put(1, 1, n + m, n + i); pos[num] = n + i; } printf("\n"); } } | cs |
반응형
'백준' 카테고리의 다른 글
[ 백준 ] 11400번 - 단절선 (C++) (0) | 2022.08.29 |
---|---|
[ 백준 ] 11266번 - 단절점 (C++) (0) | 2022.08.27 |
[ 백준 ] 1153번 - 길의 개수 (C++) (0) | 2022.08.24 |
[ 백준 ] 11286번 - 절댓값 힙 (C++) (0) | 2022.08.23 |
[ 백준 ] 3176번 - 도로 네트워크 (C++) (0) | 2022.08.22 |