luogu P4690 [Ynoi2016] 镜中的昆虫 题解

snow-panther / 2023-05-15 / 原文

P4690 [Ynoi2016] 镜中的昆虫 题解

题意

维护一个长为 \(n\) 的序列 \(a_i\),有 \(m\) 次操作。

  1. 将区间 \([l,r]\) 的值修改为 \(x\)

  2. 询问区间 \([l,r]\) 出现了多少种不同的数,也就是说同一个数出现多次只算一个。

题解

感觉这道题还是比较有意思的,像是一堆套路被集合了起来,但难写是真的难写,细节是真的多。

区间数颜色

以前我写区间数颜色是只算最右边的,然后修改前驱,但是这样写并不好扩展。
我们只计算最左边的,只我们记\(i\)的前驱为\(pre_i\),前驱是前面第一个和自己相同的数字。
然后扫描线统计区间中\([l,r]\)\(pre_i\)\([0,l-1]\)的个数,这其实是一个矩阵查询。
这其实是一个经典的二维数点问题,将\((i,pre_i)\)看做一个点,相当于查询\((x,y)(l\leq x \leq r)(0 \leq y \leq l-1)\)的点个数。
运用二维差分的知识将一个询问拆成\(4\)个,然后跑二维偏序即可,可能画图会直观一些,但是懒。

单点带修数颜色

也就是[BalkanOI2007] Mokia 摩基亚这道题。
多引入一维时间\(t\),给每一个点设置加入时间,询问设置询问时间,一个点会被统计当且仅当\(x,y,t\)都小于时才会被统计。
修改一个点可以改为插入一个点和删除一个点,修改一个点还要修改后继的前驱等,比较麻烦。

区间带修数颜色

其实对于上面的操作并不是进阶很多,我们将由于有区间推平操作,想到珂朵莉树,一个区间看做一个一个颜色段,每次修改发现只会对颜色端的两端有影响,只有颜色段两端的\(pre_i\)会被修改。
而我们知道只有修改的珂朵莉树操作次数是 n+m 级别的,所以实际上修改的并不是很多,给每一个颜色开一个珂朵莉树,给原序列开一颗珂朵莉树进行维护就行了。

一些卡常小建议:

  1. 三维偏序中结构体只需要存4个,多的放外面,可以加快排序速度。
  2. 比较短的,可以展开的函数加上inline
  3. 在三维偏序中最后一层不需要排序。