描述
有n个位置(n ≤ 50000), 每个位置有一个颜色(颜色数 ≤ 200000).
询问[L, R]区间的颜色种数.
分析
- 1. 离线树状数组统计
- HZWER:
- 将所有询问按照左端点进行排序, 将所有颜色的第一个点x, 将a[x]++, 然后从左往右扫, 扫到一个点x, 将a[next[x]]++, 碰到一个询问l,r输出sum[r]-sum[l-1], 其中sum是a数组的前缀和, 求前缀和可以用树状数组.
- 之所以这样做关键就是避免同种颜色计算多次, 这也是用树状数组解决问题的关键. 在L前的一个位置x, 如果next[x]在L之前, 用树状数组统计query(R)-query(L-1)时被减掉没有计算进去, 但之后一定会在结束对[L, R]的统计之前遇到这个next[x]; 如果next[x]在[L, R]的区间中, 那么更新next[x]之后query(R)-query(L-1)比原来大1, 也就是这个颜色被统计进去了, 而因为next[x]>L, 所以不会再遇到这个next[x]; 如果next[x]>R, 那么不会影响结果.
- 好巧妙的方式
- O(nlogn)
- 2. 莫队算法
- 分块的做法:
- 将询问分 √n 块, 每一块内按R从小到大排序, 不同块之间按L从小到大排序. 然后用两个指针{p, q}扫描, 统计[p, q]区间内每个颜色的出现次数, 同时根据当前的答案统计对[L, R]区间的颜色种数造成的影响, 直到p==L&&q==R, 当前的答案就是[L, R]区间的答案.
- 感性的理解是这样分块让指针p, q在统计某一询问移动的次数尽可能少. 至于为什么我觉得没必要证啦...
- O(n√n)
#include
#include