리뷰
업데이트를 통해 세그먼트 트리를 확장하고 구간합을 구하는 문제
https://www.acmicpc.net/problem/3653
전역 변수
- tc, n, m : 테스트 케이스의 개수 tc, 각 테케의 DVD의 수 n, 각 테케의 쿼리의 수 m
- lst : DVD의 초기정보와 인덱스 정부를 담은 정수형 벡터
- tree : 세그먼트 트리의 구간합 정보를 담은 정수형 벡터
함수
1. update
void update(int node, int s, int e, int idx, int val)
- 세그먼트 트리의 특정 인덱스의 값을 교체하고 구간합을 업데이트 하는 함수
- val은 1과 -1이 올 것이며 음수가 올 경우는 주어지지 않는다.
2. query
int query(int node, int s, int e, int L, int R)
- 구간의 합을 계산할 함수
- 1과 0으로만 이루어져 있으므로 int형 타입으로도 충분히 나타낼 수 있다.
3. init
void init()
- 각 테스트 케이스 마다 벡터를 clear해줄 함수
4. input
void input()
- n과 m을 입력받고 lst와 tree벡터를 초기화 해줄 함수
5. solution
void solution()
- 입력된 쿼리에 따라 구간합과 업데이트를 진행할 함수
- 새로운 인덱스 new_index를 세그먼트 트리의 끝인 n + 1로 초기화 해준다.
- 입력받은 수의 인덱스를 찾아 해당 인덱스 + 1 ~ n + m까지의 구간합을 구해준 뒤 출력해 준다.
- 해당 인덱스의 세그먼트 트리 노드에 -1처리를 해주어 0으로 만들어 준 뒤 구간합을 업데이트 해준다.
- 세그먼트 트리 new_index 노드에 1을 더해주고 구간합을 업데이트 해준다.
- 현재 숫자의 인덱스 값을 new_index로 새로 할당해 주고 new_index의 값을 1만큼 증가시켜 준다.
문제풀이
- tc를 입력 받고 tc만큼의 테스트 케이스를 개행해 준다.
- init 함수를 통해 이전 테스트 케이스에 사용한 lst와 tree벡터를 초기화 해준다.
- input 함수를 통해 n, m값을 받아주고 lst를 n + 1크기로, tree를 (n + m) * 4크기로 초기화 해준다. (값은 0)
- lst벡터의 인덱스에 역순으로 값을 입력받아 저장해 준다.
- update함수를 통해 lst벡터의 i번째 인덱스의 트리 노드에 1을 더해준다.
- solution함수를 통해 DVD를 꺼내고 맨 위에 올려놓는 작업을 반복해 준다.
- 각 쿼리마다 현재 DVD위에 존재하는 DVD의 갯수를 출력해 주고, 쿼리가 끝나면 줄바꿈을 실행해 준다.
- 테스트 케이스마다 위 작업을 반복해 준다.
참고 사항
- 1-based-indexing을 사용했으므로 0번 인덱스는 사용하지 않았다.
- 최악의 케이스일 경우 n + m번째 인덱스까지 처리가 필요하므로 업데이트와 쿼리는 1 ~ n + m까지 탐색을 진행한다.
- 위 사유로 인해 세그먼트 트리의 크기는 (n + m) * 4개가 있어야 인덱스 에러를 맞지 않는다.
정답 코드
#include<iostream>
#include<vector>
using namespace std;
int tc, n, m;
vector<int> lst, tree;
void update(int node, int s, int e, int idx, int val) {
if (s == idx && e == idx) {
tree[node] += val;
return;
}
int mid = (s + e) / 2;
if (s <= idx && idx <= mid) update(node * 2, s, mid, idx, val);
else update(node * 2 + 1, mid + 1, e, idx, val);
tree[node] = tree[node * 2] + tree[node * 2 + 1];
}
int query(int node, int s, int e, int L, int R) {
if (R < s || e < L) return 0;
if (L <= s && e <= R) return tree[node];
int mid = (s + e) / 2;
int left = query(node * 2, s, mid, L, R);
int right = query(node * 2 + 1, mid + 1, e, L, R);
return left + right;
}
void init() {
lst.clear();
tree.clear();
}
void input() {
cin >> n >> m;
lst.resize(n + 1);
tree.resize((n + m) * 4, 0);
for (int i = 1; i <= n; i++) {
lst[i] = n - i + 1;
update(1, 1, n + m, lst[i], 1);
}
}
void solution() {
int new_index = n + 1;
for (int i = 1; i <= m; i++) {
int a; cin >> a;
int idx = lst[a];
cout << query(1, 1, n + m, idx + 1, n + m) << " ";
update(1, 1, n + m, idx, -1);
update(1, 1, n + m, new_index, 1);
lst[a] = new_index++;
}
cout << "\n";
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> tc;
while (tc--) {
init();
input();
solution();
}
}
728x90
'알고리즘 공부 > C++' 카테고리의 다른 글
[G4] 백준 5052번 전화번호 목록 C++ 트라이, 문자열 (1) | 2024.10.08 |
---|---|
[P3] 백준 19585번 전설 C++ 트라이, 해시맵, 문자열 (1) | 2024.10.08 |
[P5] 백준 7578번 공장 C++ 세그먼트 트리 (0) | 2024.10.06 |
[G3] 백준 2533번 사회망 서비스(SNS) C++ 트리에서의 다이나믹 프로그래밍 (0) | 2024.10.06 |
[D3] SWEA 22683번 나무 베기 C++ 다익스트라, 최단 경로 (0) | 2024.10.06 |