우선 쿼리 하나에 대한 답을 수학적으로 정리해 보자. 쿼리로 바닥 카드의 구간 [li,ri]가 들어왔다고 가정하자. 해당 범위 내에 v가 적힌 카드의 수를 cv라 하고, 손 카드 중 v가 적힌 카드의 수를 dv라 하자. 이때 해당 쿼리의 답을 아래와 같이 나타낼 수 있다.
i=1∑nmin(ci,di).
문제의 풀이에 대한 직관을 유도하기 위해, 더 쉬운 부분문제를 풀어보자. 모든 di가 1이라고 가정하자. 이때, 문제는 Q개의 구간 [li,ri]에 대해 구간 내의 서로 다른 수의 개수를 구하는 문제가 된다. 이 문제를 해결하는 방법 중 하나는 문제를 2D 구간 합 문제로 환원하는 것이다. n×n 격자 G가 있다고 하고, r행 c열의 칸을 (r,c)와 같이 나타내자. 처음에 모든 칸에 0이 적혀 있다고 가정한 뒤, 다음 규칙에 맞게 격자의 일부 칸을 수정한다.
- 모든 1≤i≤n에 대해, 칸 (i,i)에 1을 더한다.
- 1≤j<k≤n이고 aj=ak이며 aj+1,…,ak−1이 모두 aj와 다른 모든 (j,k)에 대해, 칸 (j,k)에서 1을 뺀다.
이때, 구간 [l,r]의 서로 다른 수의 개수는 G의 영역 [l,n]×[1,r]의 모든 수의 합과 같다. 증명은 다음과 같다.
먼저 (i,i) 꼴의 칸에 1을 더함으로써 생기는 영향은 r−l+1과 같다. 이는 구간 [l,r]에 있는 수의 개수와 같다. 하지만, 이때 같은 수가 여러 번 더해질 수 있으므로, 어떤 수 x가 v번 등장한다면, max(v−1,0)만큼을 답에서 빼주어야 한다. 구간 [l,r]에 x가 v번 등장하며 v≥1이라 하자. 등장하는 위치들을 오름차순으로 i1,…,iv라 정의했을 때, 위의 격자 수정 규칙에 의해 칸 (i1,i2),(i2,i3),…,(iv−1,iv)에 −1이 적혀 있어야 하며, 이 모든 칸들은 [l,n]×[1,r] 범위 내에 존재한다. 또한, 만약 aj=ak=x인 (j,k)에 의해 1이 빼진 다른 격자칸들이 있다면, 해당 격자칸은 [l,n]×[1,r] 범위에 하나도 없음을 관찰할 수 있다. 따라서 값 x에 의한 −1 칸들의 총 기여량이 −(v−1)이 됨을 알 수 있고, +1 칸의 v 기여량과 상쇄되어 총 1만큼의 기여를 하게 된다.
이제 원래 문제를 해결하는 방법을 알아보자. 두 번째 격자 수정 규칙을 다음과 같이 바꾼다.
- 모든 1≤x≤n에 대해, x가 v번 등장하며, 그 위치를 오름차순으로 i1,i2,…,iv라 하자. 1≤j≤v−dx인 모든 j에 대해, 칸 (ij,ij+dx)에서 1을 뺀다.
위 증명과 같은 논리를 적용하면, 범위 [l,n]×[1,r]에서 −1 칸들에 의한 값 x의 기여량이 min(cx−dx,0)임을 알 수 있다. (여기서 cx는 범위 [l,r]에서 x의 등장 횟수를 의미한다.) +1 칸이 총 cx만큼의 기여를 하므로, 두 기여를 더해 보면 값 x의 합 기여량은 총 min(cx,dx)임을 알 수 있다. 따라서 위 풀이는 정당하다.
위 규칙으로 격자를 수정할 때, 격자 위에 0이 아닌 값을 가지는 칸이 최대 2n개이며, 이 칸들은 O(nlogn) 전처리를 통해 구할 수 있다. 이후로는 2D에서 점들 O(n)개가 주어질 때, O(q)개의 직사각형 영역 합을 구하면 되고, 이는 오프라인 쿼리와 스위핑을 이용해 O((n+q)logn)에 가능하다. 따라서, 전체 문제를 O((n+q)logn)에 해결할 수 있다.