길이가 N인 수열이 주어지고,
Q개의 구간 쿼리가 주어진다.
각 쿼리는 다음과 같다.
[s, e] 구간의 모든 값 XOR
그리고 모든 쿼리 결과를 다시 XOR한 값을 출력해야 한다.
첫째 줄
N Q
둘째 줄
a1 a2 a3 ... aN
다음 Q줄
s e
조건
1 ≤ N ≤ 1,000,000
1 ≤ Q ≤ 3,000,000
모든 쿼리 결과를 XOR한 값 출력
5 3
4 4 4 4 4
1 1
1 2
1 3
0
이 문제의 핵심은 다음이다.
구간 XOR → 누적 XOR(prefix XOR)
누적 XOR 배열을 만들면
acc[i] = a1 ^ a2 ^ ... ^ ai
이 된다.
[s, e] = acc[e] ^ acc[s-1]
이 공식을 이용하면
구간 XOR을 O(1)에 구할 수 있다.
나는 입력을 받으면서 누적 XOR을 바로 계산했다.
import java.util.*;
class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int Q = sc.nextInt();
int[] nums = new int[N+1];
int sum = 0;
int xor = 0;
for(int i = 1; i < N+1; i++) {
sum ^= sc.nextInt();
nums[i] = sum;
}
for(int j = 0; j < Q; j++) {
int start = sc.nextInt();
int end = sc.nextInt();
xor ^= (nums[end] ^ nums[start-1]);
}
System.out.println(xor);
}
}
강의에서는 배열을 먼저 저장한 뒤
누적 XOR 배열을 따로 만들었다.
import java.util.Scanner;
class Main
{
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int M = sc.nextInt();
int[] arr = new int[N + 1];
for (int i = 1; i <= N; i++)
arr[i] = sc.nextInt();
int[] acc = new int[N + 1];
for (int i = 1; i <= N; i++)
acc[i] = acc[i - 1] ^ arr[i];
int ans = 0;
while (M-- > 0) {
int i = sc.nextInt();
int j = sc.nextInt();
ans ^= acc[j] ^ acc[i - 1];
}
System.out.println(ans);
}
}
sum ^= sc.nextInt();
nums[i] = sum;
→ 입력과 동시에 누적 XOR 계산
arr[i] 저장 → acc[i] 따로 계산
→ 입력과 누적합을 분리
| 방식 | 특징 |
|---|---|
| 내 코드 | 한 번에 처리 |
| 강의 코드 | 단계 분리 |
입력 + 누적합 동시에 처리
→ 코드가 짧음
입력 → 누적합 → 쿼리 처리
→ 구조가 명확
두 코드 모두
acc[j] ^ acc[i-1]
을 사용한다.
즉,
풀이 방식은 완전히 동일
이 문제에서 중요한 것은
입력 속도
이다.
조건
Q ≤ 3,000,000
→ Scanner는 느릴 수 있음
Scanner → 입력 속도 느림
Scanner를 쓰지만
실전에서는 보통
BufferedReader
를 사용해야 안정적이다.
acc[i] = acc[i-1] ^ arr[i]
[s, e] = acc[e] ^ acc[s-1]
A ^ A = 0
A ^ 0 = A
이 성질 때문에 누적 XOR이 가능하다.
전체
O(N + Q)
이 문제는 구간 합 문제의 XOR 버전이다.
핵심은
누적합 → XOR로 변환
이다.
내 코드와 강의 코드는 방식은 동일하지만
구조만 다르다.
내 코드 → 입력과 누적합 동시에 처리
강의 코드 → 단계 분리
또한 이 문제에서 중요한 포인트는
입력 속도
이다.
즉,
BufferedReader 사용이 안정적
이라는 점도 함께 기억해야 한다.