首页 > 技术文章 > 【基本操作】主席树统计区间不同颜色个数

scx2015noip-as-php 2018-11-22 20:44 原文

例题:询问 $n$ 个数中无修改的区间不同数个数,不带修改(SPOJ的一道题)。

方法1:直接删

我们尝试头铁地开正常的下标主席树!

依次插入 $n$ 个数,插入第 $i$ 个数时,我们只要在把第 $i$ 个版本的主席树的第 $i$ 位 $+1$ 就可以了,表示多出一个数。

但前面与它相同的数怎么处理?

可以记录每个数上一次出现的位置,在当前版本的主席树中,给当前位 $+1$ 后,把上一次出现相同数的位置 $-1$,这样就不会被算重复了。

如果数过大,离散化一下就好了。

然后对于 $[left,right]$ 这样的区间询问,在第 $right$ 个版本的线段树上查询 $[left,right]$ 的和即可。

方法2:考虑差分思想。

如果我们保守,就换用权值主席树。

做过 $APIO 2018\space T1$ (的我)即可了解这种思路(那道题让你用判断一个区间内是否包含所有颜色,做法有些类似)。

就是你直接把主席树第 $i$ 个位置的权值 $pre$ 设为这位的数上一次出现的位置。然后查询一个区间 $[l,r]$ 的颜色数 其实就是查询区间 $[1,r]$ 有多少个 $pre$ 值 $\lt l$(直接查 $[1,r]$ 是为了方便,答案不变,但不用再写个数据结构维护)。

重点就是动态查询前缀中 有多少个数 小于一个给定数,每次在主席树的第 $r$ 个版本上查权值主席树中 有多少个数小于 $l$ 就完事了。

这两个做法都可以直接改成朴素线段树模拟+离线回答询问(每达到一个右端点就回答询问)。也就是说这里强行转化成主席树讲。

 

例题:一棵树,每个点都有一种颜色,每次询问以一个点为根的子树中的不同颜色数。

用 $dfs$ 序建主席树的版本 及 使用主席树的下标,然后只能用上例的方法2维护(一个点要从它的父亲的版本转移过来,定义一个数上一次出现的位置为 它在当前点的祖先中与这个数相等且离这个数所在点最近的点),查询子树 转为 查询子树对应的 $dfs$ 序区间 即可。

推荐阅读