一些数据结构维护手法,好题

一些数据结构维护手法,好题

[蓝桥杯 2022 国 AC] 替换字符

发现字母的变换有复合性质,可以用线段树维护一个 \(lazy[26]\) 数组表示这个区间的每一个字母变成了那一个。

当两个标记合并的时候有:\(nwlazy[i]=blazy[alazy[i]]\),相当于标记信息的复合。


One Occurrence

对于这种某个数只出现一次的经典题,考虑一个经典的 trick,我们维护一个 \(pre[i]\) 表示 \(a_i\) 上一次出现的位置,然后 \(suf[i]\) 表示 \(a_i\) 下一次出现的位置。

我们发现若 \(a_i\) 在区间 \([l,r]\) 中只出现了一次 \(\iff pre[i]<l \ or\ suf[i]>r\)

我们发现这样我们不好处理,因为多了个 \(suf\) 的情况,我们不难想到如果能固定 \(r\),是不是问题就好解决了。

利用扫描线思想,我们把询问离线下来,扫 \(r\), 然后去维护 \(l\) 的答案。

我们用一个线段树,维护区间 \(pre[i]\) 的最小值。

对于扫到某个位置 \(r\),我们把 \(r\) 这个位置在线段树中的值改为 \(pre[r]\),然后注意此时还要把 \(pre[r]\) 位置的值改为 \(INF\),因为此时如果 \(pre[r]\) 位置的数的 \(pre\) 是满足条件的,但又因为在 \(r\) 处还出现了一次,所以此时他在所有以 \(r\) 为右端点的询问中,一定是不合法的,所以我们要改为 \(INF\)


A Simple Task

题目要求我们对区间的所有字母排序(升序或者降序),我们不难发现其实本质就是按 \(26\) 个字母的顺序依次给区间赋值。

每次区间修改就是遍历 \(26\) 个字母,在其对应的线段树上修改。

所以我们可以用线段树维护每种字母的出现次数。

故我们开 \(26\) 个线段树,每颗线段树维护对应字母的出现次数,然后支持区间赋值即可。


laoya 的有根树

很容易想到离线,我们可以先把整颗树建好,那么增加一个点和删除一个点,都相当于在树上修改权值,当一个叶子被删除的时候,其到根结点上的整条链上的 \(g\) 值都要减少,增加也是同理。

对于 \(g(i)\times g(j)\) 的最大值,我们不难想到当 \(g(i),g(j)\) 取最大两个,或者取最小两个的时候可以得到最优解。

所以我们不难想到维护树上的最大,次大,最小,次小。

而且还要支持子树查询,链上修改。

我们很容易想到树链剖分+线段树维护。(这里要注意边界,例如当子树内只有一个数的时候,次大和次小是不存在的,要弄成无穷,当增加或者删除的时候,要注意边界的修改)


数组划分

考虑没有修改怎么做,我们可以仿照最大字段和的思路,令 \(f_i\) 为以 \(i\) 为右端点的最大美值,\(g_i\) 表示前缀 \(1\backsim i\)\(f_i\) 的最大值。

不难得到如下转移方程:

  • \(f_i=\max(f_{i-1}+a_i,f_{i-2}+3\times a_i - 2\times a_{i-1}, a_i, 3\times a_i - 2\times a_{i-1})\)
  • \(g_i=\max(g_{i-1}, f_i)\)

然后考虑修改,这是一个经典的动态 DP,我们把 DP 的转移看成一个\(\max+\)矩阵,直接用线段树维护即可。

\(\begin{bmatrix}f_{i-2}&f_{i-1}&g_{i-1}&0&0\end{bmatrix}\times\begin{bmatrix}-inf&3a_i-2a_{i-2}&3a_i-2a_{i-2}&-inf&-inf\\0&a_i&a_i&-inf&-inf\\-inf&-inf&0&-inf&-inf\\-inf&a_i&a_i&0&-inf\\-inf&3a_i-2a_{i-1}&3a_i-2a_{i-1}&-inf&0\end{bmatrix}=\begin{bmatrix}f_{i-1}&f_{i}&g_{i}&0&0\end{bmatrix}\)

每次单点修改,相当于修改与 \(a_i\) 有关的系数矩阵:\(A_i\)\(A_{i+1}\)

最后答案就为:\(\begin{bmatrix}-inf&-inf&-inf&0&0\end{bmatrix}\times A\)(其中 \(A\) 即为整个区间的矩阵)。

posted @ 2024-04-05 16:54  jackle  阅读(3)  评论(0编辑  收藏  举报