BOJ 34905 Quantum Beaver
문제 내용
최초에 0으로 채워진 길이 의 1차원 배열이 있습니다. 당신은 어떤 계획에 따라 배열의 값을 바꾸려고 합니다. 이 계획은 개의 단위 계획으로 이루어져 있으며, 하나의 단위 계획은 다음과 같습니다.
- (, , ) : 번째 날에, 배열의 번째부터 번째까지의 원소를 로 바꿉니다.
들은 모두 서로 다릅니다.
그런데 당신은 라플라스의 악마의 저주에 걸렸기 때문에, 이 계획을 실행하기 전에 모든 단위 계획의 가 로 바뀌게 됩니다. 은 이상 미만의 정수 중에서 랜덤으로 정해진 수입니다.
의 값이 정해졌을 때 최종 배열의 모든 원소의 합을 이라고 할 때, 의 값을 구하세요.
입력
첫 줄에는 테스트 케이스의 개수 가 주어집니다. ()
각 테스트 케이스의 첫 줄에는 , , 가 주어집니다. (, , 1 \le Q \le \min(2^K, 200;000)$)
그 다음 줄에 걸쳐서 각 줄에 하나의 단위 계획을 나타내는 , , , 가 주어집니다.
의 총합과 의 총합은 각각 을 초과하지 않습니다.
출력
각 테스트 케이스에 대해, 문제의 정답을 로 나눈 나머지를 한 줄에 출력합니다.
문제 풀이
스포일러
이 문제는 비트 트라이에 세그먼트 트리를 얹어서 풀 수 있습니다.
인 경우의 문제를 풀 수 있고 각각의 를 넣고 빼는 쿼리를 처리할 수 있다면, 문제가 요구하는 식에서 합의 순서를 바꿔 1번째 원소가 가질 수 있는 가능한 모든 수의 합, …, 번째 원소가 가질 수 있는 가능한 모든 수의 합을 구해서 문제를 풀 수 있을 것입니다.
배열에서 어떤 자리가 최종적으로 가 되는 경우의 수는 다음과 같이 구해집니다.
- 들 중에서 번째 비트가 와 다른 것이 있다면, 그 비트는 XOR 결과 1이 되어야 하므로 전체 경우의 수가 절반으로 나눠집니다.
- 그러한 것이 없다면 전체 경우의 수는 그대로 다음 비트로 전파됩니다. 이는 역으로 생각하면 그 비트를 제외한 가지 중에서 계산한 경우의 수에 2배를 한 것과 같습니다.
- 트라이를 따라가면서 이 과정을 반복합니다.
일단 의 목록이 사전에 정해져 있으므로 이들 값을 모두 포함하는 트라이를 만들고, 각 노드에 대해 그 노드에서 도달할 수 있는 리프 중에서 현재 켜져 있는 의 개수를 저장합니다. 그러면 각 노드에서 그 노드 아래의 리프들이 총합에 기여하는 값을 세그먼트 트리와 같은 방식으로 구할 수 있습니다.
- 리프에는 를 저장합니다.
- 어떤 노드의 자식이 두 개이고 그 둘이 모두 비어 있지 않다면, 양쪽의 값을 더해 줍니다.
- 둘 중 한 쪽이 비어있다면, 반대쪽 값을 2배 해서 저장합니다. 둘 다 비어있다면 이 노드의 값은 0입니다.
- 자식이 한 개라면 그 자식의 값을 2배 해서 저장합니다.
를 하나 켜고 끄는 업데이트는 리프를 먼저 업데이트하고 루트 방향으로 따라가면서 모든 값을 업데이트해주면 됩니다. 이 업데이트를 이용해서 배열의 인덱스 방향으로 스위핑하여 각 인덱스에서의 총합을 모두 구하면 문제의 정답을 구할 수 있습니다.
이대로 구현 시 마지막 서브태스크에서 시간 초과를 받는다면, 연속으로 자식이 한 개인 구간들을 한 번에 건너뛸 수 있도록 추가 처리를 해주면 통과합니다.