---
title: "AtCoder Beginner Contest 242 G(莫隊)"
tags: 題解, 離線
---
https://atcoder.jp/contests/abc242/tasks/abc242_g
#### 題意
給 $N$ 個數 $a_1, a_2, ..., a_N$,每個數的範圍在 $1$ ~ $N$ 之間。給 $Q$ 個查詢,每個查詢是 $l$ 和 $r$,求 $a_l, ..., a_r$ 中,有多少組 pair ($a_i$, $a_j$) 滿足 $a_i = a_j$,其中每個 $a_i$ 不可重複使用。
#### 思路
對於區間 $(L, R)$,假設我們知道它的答案,則可以用很快的速度得知相鄰的區間 $(L-1, R)$、$(L+1, R)$、$(L,R-1)$、$(L, R+1)$ 的答案(how: 維護各數字出現的頻率)。因此這題可以用莫隊做。
用莫隊時只需要寫好 $add(i)$、$remove(i)$、$out(i)$ 即可。
- $add(i)$:將該數字頻率加一,若頻率原本是奇數則答案加一
- $remove(i)$:將該數字頻率減一,若頻率變為奇數則答案減一
- $out(i)$:即目前的答案個數
複雜度為 $O(N\sqrt{Q})$。
#### Code
```python=1
class Mo:
def __init__(self, n):
self.n = n
self.q = 0
self.queries = []
def add_query(self, ql, qr):
# [ql, qr]
self.queries.append((ql, qr))
self.q += 1
def solve(self):
def add(idx):
nonlocal cur
cur += freq[A[idx]] & 1
freq[A[idx]] += 1
def remove(idx):
nonlocal cur
freq[A[idx]] -= 1
cur -= freq[A[idx]] & 1
def out(idx):
ans[idx] = cur
queries = self.queries
SZ = 128
NUM = (self.n + SZ - 1) // SZ
B = [[] for _ in range(NUM)]
for qi, (ql, qr) in enumerate(queries):
B[ql // SZ].append(qi)
for bi in range(NUM):
B[bi].sort(key=lambda qi: queries[qi][1], reverse=bi & 1)
L, R = 0, -1
ans = [0 for _ in range(self.q)]
cur = 0
freq = [0 for _ in range(self.n + 1)]
for qis in B:
for qi in qis:
ql, qr = queries[qi]
for i in range(L, ql):
remove(i)
for i in range(L - 1, ql - 1, -1):
add(i)
for i in range(R + 1, qr + 1):
add(i)
for i in range(R, qr, -1):
remove(i)
L, R = ql, qr
out(qi)
return ans
def solve():
N = int(input())
global A
A = list(map(int, input().split()))
mo = Mo(N)
Q = int(input())
for _ in range(Q):
l, r = map(int, input().split())
l -= 1; r -= 1
mo.add_query(l, r)
ans = mo.solve()
print(*ans, sep="\n")
if __name__ == "__main__":
solve()
```