리뷰
구간 대체 업데이트, 구간 합, 느린 갱신, 오일러 경로 테크닉을 활용해야 하는 문제
https://www.acmicpc.net/problem/18437
전역 변수
- n, m : 직원의 수 n, 쿼리의 수 m
- MAX_N : 주어지는 n값의 최대치를 나타낼 정수형 상수 변수, 100001로 초기화 한다.
- tree : 세그먼트 트리 정보를 저장할 정수형 배열, MAX_N * 4크기로 초기화
- lazy : 세그먼트 트리 업데이트 정보를 저장할 정수형 배열, MAX_N * 4크기로 초기화
- path : 부하 직원을 인접리스트로 저장할 정수형 벡터, MAX_N크기로 초기화
- it : 서브 트리에서 해당 노드에 진입한 시간을 기록할 정수형 배열, MAX_N크기로 초기화
- ot : 서브 트리에서 해당 노드에서 빠져나온 시간을 기록할 정수형 배열, MAX_N크기로 초기화
- timer : 시간 정보를 저장할 정수형 변수
함수
1. dfs
void dfs(int boss)
각 직원에 다다른 시간을 저장할 깊이 우선 탐색 함수
- boss를 매개변수로 받아 it[boss]에 timer + 1값을 저장한다.
- 자신의 인접리스트에 존재하는 자식 노드에게 dfs를 수행한다.
- 모든 자식에게 재귀가 마친 후에 ot[boss]에 timer값을 저장한다.
2. build
void build(int node, int s, int e)
세그먼트 트리에 초깃값을 적용시킬 함수
- 세그먼트 트리의 리프노드에 1을 저장하고 각 상위 노드에 구간합을 저장해 준다.
3. propagate
void propagate(int node, int s, int e)
갱신할 업데이트가 있는지 확인하고 있다면 구간 업데이트를 진행해 주는 함수
- 현재 노드에 lazy값이 존재하다면 업데이트를 진행해 준다.
- lazy값이 1이라면 현재 노드를 구간의 길이로 변경해 준다.
- lazy값이 -1이라면 현재 노드를 0으로 변경해 준다.
- 현재 노드가 리프노드가 아니라면 하위 노드에 lazy값을 전파해 준다.
- 전파를 마친 후에는 현재 노드의 lazy값을 0으로 초기화 해준다.
4. update
void update(int node, int s, int e, int L, int R, int val)
구간 업데이트를 진행할 함수
- 함수가 호출되면 현재 노드와 탐색 범위를 propagate의 매개변수로 전달하여 실행해 준다.
- 업데이트 범위를 벗어나면 return 처리해 준다.
- 업데이트 범위에 들어왔다면 lazy에 val을 전달해 준 후에 propagate를 실행해 준 뒤 리턴해 준다.
- 범위가 걸칠 경우 이분 탐색을 통해 좌우로 업데이트를 재귀로 수행해 준다.
- 재귀가 모두 완료되었을 경우 세그먼트 트리에 저장된 구간합을 업데이트 해준다.
5. query
int query(int node, int s, int e, int L, int R)
구간합을 구한 뒤 리턴해 주는 함수
- 마찬가지로 함수가 호출되면 propagate 함수를 호출해 남아있는 업데이트를 적용시켜 준다.
- 범위를 벗어나면 0을 리턴해 준다.
- 유효한 범위일 경우 세그먼트 트리에 저장된 현재 노드의 값을 리턴해 준다.
- 범위가 걸칠 경우 이분탐색을 통해 재귀적으로 왼쪽 및 오른쪽의 값을 구한 뒤 더해서 리턴해 준다.
문제풀이
- n값을 입력 받아 인접리스트를 역방향으로 만들어 준다.
- build함수를 통해 세그먼트 트리를 기본값인 1로 업데이트 해준다.
- dfs함수를 통해 대표 번호인 1을 매개변수로 전달하여 it, ot배열을 최신화 해준다.
- m값을 입력 받아 m개 만큼의 while문을 실행하고 order 및 idx값을 입력 받는다.
- order가 1일 경우 it[idx] + 1, ot[idx]까지의 범위에 lazy값을 1로 전달한다.
- order가 2일 경우 it[idx] + 1, ot[idx]까지의 범위에 lazy값을 2로 전달한다.
- order가 3일 경우 it[idx] + 1, ot[idx]까지의 범위의 구간합을 출력해 준다.
참고 사항
- 가장 처음에 컴퓨터는 켜져있는 상태이다.
- 모든 쿼리는 자기 자신을 포함하지 않는다.
정답 코드
#include<iostream>
#include<vector>
using namespace std;
int n, m;
const int MAX_N = 100001;
int tree[MAX_N * 4];
int lazy[MAX_N * 4];
vector<int>path[MAX_N];
int it[MAX_N];
int ot[MAX_N];
int timer;
void dfs(int boss) {
it[boss] = ++timer;
for (int child : path[boss]) dfs(child);
ot[boss] = timer;
}
void build(int node, int s, int e) {
if (s == e) tree[node] = 1;
else {
int mid = (s + e) / 2;
build(node * 2, s, mid);
build(node * 2 + 1, mid + 1, e);
tree[node] = tree[node * 2] + tree[node * 2 + 1];
}
}
void propagate(int node, int s, int e) {
if (lazy[node]) {
if (lazy[node] == 1) {
tree[node] = e - s + 1;
}
else if (lazy[node] == -1) {
tree[node] = 0;
}
if (s != e) {
lazy[node * 2] = lazy[node];
lazy[node * 2 + 1] = lazy[node];
}
lazy[node] = 0;
}
}
void update(int node, int s, int e, int L, int R, int val) {
propagate(node, s, e);
if (R < s || e < L) return;
if (L <= s && e <= R) {
lazy[node] = val;
propagate(node, s, e);
return;
}
int mid = (s + e) / 2;
update(node * 2, s, mid, L, R, val);
update(node * 2 + 1, mid + 1, e, L, R, val);
tree[node] = tree[node * 2] + tree[node * 2 + 1];
}
int query(int node, int s, int e, int L, int R) {
propagate(node, s, e);
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;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) {
int boss; cin >> boss;
path[boss].push_back(i);
}
build(1, 1, n);
dfs(1);
cin >> m;
while (m--) {
int order, idx; cin >> order >> idx;
if (order == 1) update(1, 1, n, it[idx] + 1, ot[idx], 1);
else if (order == 2) update(1, 1, n, it[idx] + 1, ot[idx], -1);
else cout << query(1, 1, n, it[idx] + 1, ot[idx]) << "\n";
}
}
728x90
'알고리즘 공부 > C++' 카테고리의 다른 글
[S2] 백준 2961번 도영이가 만든 맛있는 음식 C++ 백트래킹 (1) | 2024.10.15 |
---|---|
[G5] 백준 15686번 치킨 배달 C++ 백트래킹, 브루트포스 알고리즘, 구현, 플러드필 (0) | 2024.10.15 |
[P3] 백준 14268번 회사 문화 2 C++ 세그먼트 트리, 오일러 경로 테크닉, 느리게 갱신되는 세그먼트 트리 (3) | 2024.10.13 |
[G2] 19236번 청소년 상어 C++ 백트래킹, 시뮬레이션, 구현, 재귀 (0) | 2024.10.13 |
[G4] 백준 2056번 작업 C++ 위상 정렬 (2) | 2024.10.12 |