문제 정보
- 문제: https://www.acmicpc.net/problem/15782
- 요약: N개 정점의 트리(루트 1)가 주어지고, 각 정점이 가중치를 가집니다. M개의 쿼리 중 Type 1은 정점 x의 부분트리 전체 가중치의 XOR 합을 구하고, Type 2는 정점 x의 부분트리의 모든 가중치에 y를 XOR합니다.
- 제한: 시간 1초, 메모리 512MB, 3 ≤ N ≤ 100,000, 3 ≤ M ≤ 500,000, 0 ≤ weight, y ≤ 10,000
입출력 형식/예제
| |
예제 설명:
- 초기 트리: 1-2-3-5, 2-4 구조, 가중치 [1,2,3,4,5]
- 쿼리 1: 노드 1의 부분트리(전체) XOR = 1^2^3^4^5 = 1
- 쿼리 2: 노드 3의 부분트리에 100 XOR → 가중치 변경
- 쿼리 4: 노드 4의 부분트리(자신뿐) = 4
접근 개요
핵심 관찰:
- 부분트리는 연결된 구간으로, DFS 탐색 순서에서 연속된 구간을 이룹니다.
- XOR 연산의 특성: 홀수 개 원소에만 값이 영향을 줍니다. (a ⊕ a = 0)
- 트리를 평탄화하면 일렬 배열로 변환되어 세그먼트 트리 사용 가능합니다.
선택 근거:
- Naive 부분트리 순회: O(M·N) → TLE
- Euler Tour + Lazy SegTree: O((N+M)log N) → AC
알고리즘 설계
1단계: Euler Tour로 트리 평탄화
DFS 탐색을 통해 각 노드의 진입/진출 시간을 기록합니다.
in_time[u]: 노드 u 방문 시 시각out_time[u]: 노드 u의 부분트리 탐색 완료 시각- 부분트리 = 연속 구간
[in_time[u], out_time[u]]
| |
2단계: Lazy Propagation 세그먼트 트리
핵심 문제: XOR은 합산이 아닌 토글이므로, 원소 개수가 홀수/짝수인지가 중요합니다.
| |
이유:
- 짝수 개 원소:
a ⊕ a = 0이므로 XOR이 상쇄됨 - 홀수 개 원소: 하나가 남아
result ⊕ val이 적용됨
쿼리 처리
- Type 1 (조회):
query(in_time[x], out_time[x])로 부분트리 XOR 합 반환 - Type 2 (업데이트):
update(in_time[x], out_time[x], y)로 구간에 y XOR
복잡도 분석
| 작업 | 시간 | 공간 |
|---|---|---|
| Euler Tour (DFS) | O(N) | O(N) |
| 세그먼트 트리 구축 | O(N log N) | O(N) |
| 각 쿼리 처리 | O(log N) | - |
| 전체 | O((N+M) log N) | O(N) |
구현
| |
코너 케이스 체크리스트
| 경우 | 처리 방식 |
|---|---|
| 리프 노드 조회 | out_time[u] == in_time[u] → 자신의 가중치만 반환 |
| 루트 조회 | 전체 트리 XOR 계산 |
| 전체 부분트리 업데이트 | 구간의 모든 노드 토글 |
| y = 0 업데이트 | XOR 상쇄로 변화 없음 (정상 동작) |
| 홀수/짝수 크기 구간 | push 함수에서 원소 개수로 판별 |
| 다중 업데이트 누적 | Lazy propagation으로 병합 |
제출 전 점검
- ✅ XOR lazy push에서 원소 개수(홀수/짝수) 확인
- ✅ in_time, out_time 초기화 및 DFS 정상 작동
- ✅ 세그먼트 트리 노드 범위 오버플로 방지 (MAXN*8)
- ✅ 각 쿼리 타입별 입력 형식 정확성
- ✅ Long long 필요 여부 검토 (10000 범위이므로 int 충분)
![Featured image of post [Algorithm] C++ 백준 15782번: Calculate! 2](/post/algorithm/2025-12-02-boj-15782-calculate-2-tree-segtree-lazy-cpp-solution/wordcloud_hu_5572569251d5a431.png)
![[Algorithm] C++ 백준 13925 수열과 쿼리 13](/post/algorithm/2025-12-02-boj-13925-sequence-query-13-segtree-cpp-solution/wordcloud_hu_ff7e3b65400ed471.png)
![[Algorithm] C++ 백준 14504번: 수열과 쿼리 18](/post/algorithm/2025-12-02-boj-14504-sequence-query-18-segtree-cpp-solution/wordcloud_hu_fcca398ee98a773d.png)
![[Algorithm] C++ 백준 15782번: Calculate! 2](/post/algorithm/2025-12-02-boj-15782-calculate-2-tree-segtree-lazy-cpp-solution/wordcloud_hu_c7b151aaf16cbe10.png)
![[Algorithm] C++ 백준 16496번: 큰 수 만들기](/post/algorithm/2025-12-02-boj-16496-largest-number-greedy-sorting-cpp-solution/wordcloud_hu_9f9372bd1ae0bc2e.png)
![[Algorithm] C++ 백준 1725번: 히스토그램](/post/algorithm/2025-12-02-boj-1725-histogram-maxarea-stack-cpp-solution/wordcloud_hu_a9b77b8cde0366cb.png)
![[Algorithm] C++ 백준 17429번: 국제 메시 기구](/post/algorithm/2025-08-14-boj-17429-international-messi-organization-hld-lazy-segtree-cpp-solution/wordcloud_hu_6ebd6ef8983e9f39.png)
![[Algorithm] C++ 백준 24272번: 루트 노드가 많은 트리일수록 좋은 트리이다](/post/algorithm/2025-08-14-boj-24272-more-root-nodes-better-tree-cpp-solution/wordcloud_hu_41642d1d3a56b905.png)
![[Algorithm] C++ 백준 18227번: 성대나라의 물탱크](/post/algorithm/2025-08-14-boj-18227-water-tank-tree-bit-cpp-solution/wordcloud_hu_819b0818d46dd706.png)
![[Algorithm] C++ 백준 11932번: 트리와 K번째 수 - PST+LCA](/post/algorithm/2025-08-14-boj-11932-tree-kth-number-pst-lca-cpp-solution/wordcloud_hu_a44ec252ecd7c8a9.png)
![[Algorithm] C++ 백준 13538번: XOR 쿼리 - 퍼시스턴트 트라이](/post/algorithm/2025-08-14-boj-13538-xor-query-persistent-trie-cpp-solution/wordcloud_hu_672c93ae9f970898.png)