인덱스가 i -> i xor x로 재배열(permutation) 되는 상황에서, 구간 XOR 질의를 빠르게 처리해야 한다.
핵심은 배열을 2의 거듭제곱 크기로 0 패딩하면 XOR 재배열이 “각 비트 레벨에서 좌/우 서브트리를 교환하는 것”으로 바뀌고, 세그먼트 트리에서 그대로 구간 질의를 할 수 있다는 점이다.
문제 정보
문제 링크: https://www.acmicpc.net/problem/24271
문제 요약:
- 길이 \(N\) 수열 \(A_0..A_{N-1}\)가 주어진다.
- 쿼리 1:
1 l r x에 대해 \(l \le (i \oplus x) \le r\) 를 만족하는 모든 \(i\) (단 \(0 \le i < N\))의 \(A_i\)를 XOR한 값을 출력한다. 없으면 0. - 쿼리 2:
2 i x는 \(A_i \leftarrow A_i \oplus x\) 로 갱신한다.
제한 조건:
- 시간 제한: 1초
- 메모리 제한: 1024MB
- \(1 \le N, Q \le 200{,}000\)
- \(0 \le A_i < 2^{31}\)
1번 쿼리: \(0 \le l \le r < N\), \(0 \le x < N\)2번 쿼리: \(0 \le i < N\), \(0 \le x < 2^{31}\)
입출력 예제
입력 1:
| |
출력 1:
| |
접근 방식
핵심 관찰 1: 쿼리 1은 “XOR-퍼뮤테이션된 배열의 구간 XOR”이다
조건 \(l \le (i \oplus x) \le r\) 를 만족하는 \(i\)만 XOR한다는 것은, 값의 관점에서
- \(B_j = A_{j \oplus x}\) 라는 새 배열 \(B\)를 생각하면
- 쿼리 1의 답은 \(B_l \oplus B_{l+1} \oplus \cdots \oplus B_r\)
와 같다. 즉, **고정된 \(x\)**에 대해 “인덱스를 XOR로 재배열한 배열에서의 구간 XOR”을 매번 빠르게 계산하면 된다.
핵심 관찰 2: \(N\)이 2의 거듭제곱이 아니면 0으로 패딩해도 답은 변하지 않는다
\(M = 2^k \ge N\) 인 최소 거듭제곱을 잡고, \(A_N..A_{M-1}\) 를 모두 0으로 둔다.
그러면 쿼리의 조건 \(l,r < N \le M\) 이므로 “존재하지 않는 인덱스”는 값이 0이라 XOR 결과에 영향을 주지 않는다.
결론적으로 **길이 \(M\)**의 배열에 대해 동일한 쿼리를 처리해도 정답이 유지된다.
핵심 관찰 3: XOR-퍼뮤테이션은 세그먼트 트리에서 “레벨별 자식 스왑”이다
세그먼트 트리에서 어떤 노드는 “상위 비트 prefix가 고정된 연속 구간”을 나타낸다.
인덱스에 \(x\)를 XOR하면, 각 비트 레벨에서
- 해당 비트가 0이면 구간이 같은 쪽(좌/우)에 그대로 남고
- 해당 비트가 1이면 좌/우가 서로 교환(swap) 된다.
따라서 \(B\)에서 구간 \([l,r]\)를 질의할 때, 트리를 내려가며 \(x\)의 비트가 1인 레벨에서만 자식을 바꿔 타면 원래 배열 \(A\)의 세그먼트 트리로도 같은 XOR을 얻는다.
알고리즘 설계 (Mermaid Flowchart)
flowchart TD
A["입력: N, 배열 A, Q개 쿼리"] --> B["M = N 이상의 최소 2의 거듭제곱, A를 길이 M으로 0 패딩"]
B --> C["세그먼트 트리에 A 저장 (노드 값 = 구간 XOR)"]
C --> D{"쿼리 타입?"}
D -- "2 i x" --> E["리프 i에 A[i] ^= x 로 갱신 (위로 XOR 재계산)"]
D -- "1 l r x" --> F["query(l,r,x): 내려가며 x의 비트가 1이면 자식 방문 순서를 swap"]
E --> D
F --> G["출력: XOR 결과"]
G --> D
단계별 로직
- 패딩: \(M\)을 2의 거듭제곱으로 맞추고 \(A\)를 0으로 확장한다.
- 세그먼트 트리 구축: 각 노드는 담당 구간의 XOR을 저장한다.
- 갱신(쿼리 2): 인덱스 \(i\)의 값을 \(A_i \oplus= x\)로 바꾸는 것은 XOR 갱신이므로 리프에서 XOR하고 위로 갱신한다.
- 질의(쿼리 1): \([l,r]\)를 내려가며 만나는 레벨의 비트에 대해, \(x\)의 해당 비트가 1이면 좌/우 서브트리의 의미가 바뀌므로 재귀 호출을 서로 바꿔 방문한다.
복잡도 분석
| 항목 | 복잡도 | 비고 |
|---|---|---|
| 시간 복잡도 | \(O((N+Q)\log M)\) | \(M \le 2N\), 각 쿼리/갱신은 트리 높이만큼 |
| 공간 복잡도 | \(O(M)\) | 세그먼트 트리 배열(상수 배) |
코너 케이스 및 실수 포인트
| 케이스 | 설명 | 처리 방법 |
|---|---|---|
| N이 2의 거듭제곱이 아님 | XOR 퍼뮤테이션이 [0, N)에서 닫히지 않을 수 있음 | \(M\)으로 0 패딩 후 처리 |
| 해당 i가 하나도 없음 | 쿼리 1 조건을 만족하는 i가 없을 수 있음 | XOR 항이 0개면 0 출력(기본값 0) |
| x의 상위 비트 | \(x < N \le M\) 이지만, 트리 높이는 \(\log M\) | 트리 레벨(최상위 비트) 기준으로만 확인 |
| 값 범위 | \(A_i < 2^{31}\), XOR는 오버플로우 개념 없음 | uint32_t/int로 안전 |
구현 코드 (C++)
| |
![Featured image of post [Algorithm] C++ 백준 24271번: xor²](/post/algorithm/2026-01-24-boj-24271-xor-squared-xor-permutation-segment-tree-cpp-solution/wordcloud_hu_9145557091019e18.png)
![[Algorithm] C++ 백준 14288번: 회사 문화 4](/post/algorithm/2026-01-24-boj-14288-company-culture-4-tree-queries-fenwick-cpp-solution/wordcloud_hu_71f27d76781ea5f9.png)
![[Algorithm] C++ 백준 24271번: xor²](/post/algorithm/2026-01-24-boj-24271-xor-squared-xor-permutation-segment-tree-cpp-solution/wordcloud_hu_26a096bd3c9cd391.png)
![[Algorithm] C++ 백준 25172번: 꼼꼼한 쿠기의 졸업여행](/post/algorithm/2026-01-24-boj-25172-graduation-trip-dynamic-connectivity-dsu-offline-cpp-solution/wordcloud_hu_e9b1b16e9501050b.png)
![[Algorithm] C++ 백준 18874번: Haircut](/post/algorithm/2026-01-05-boj-18874-haircut-fenwick-tree-inversion-cpp-solution/wordcloud_hu_ff0c2f02e81b4f7e.png)
![[Algorithm] C++ 백준 9120번: Oulipo 다국어](/post/algorithm/2026-01-05-boj-9120-oulipo-multilingual-kmp-string-matching-cpp-solution/wordcloud_hu_801cf29e8e8a768d.png)
![[Algorithm] C++ 백준 3006번: 터보소트](/post/algorithm/2025-12-19-boj-3006-turbosort-cpp-solution/wordcloud_hu_178815acefb3fc18.png)
![[Algorithm] C++ 백준 16895번: 님 게임 3](/post/algorithm/2025-12-19-boj-16895-nim-game-3-cpp-solution/wordcloud_hu_2a3702a054db4652.png)
![[Algorithm] C++ 백준 1777번: 순열복원](/post/algorithm/2025-12-19-boj-1777-permutation-recovery-cpp-solution/wordcloud_hu_5cc423cda339f0d4.png)
![[Algorithm] C++/Python 백준 16993번: 연속합과 쿼리 (세그먼트 트리)](/post/algorithm/2025-09-16-boj-16993-maximum-subarray-queries-segment-tree-cpp-python-solution/wordcloud_hu_a7b6092fd0960f53.png)