20250204 数据结构杂题(上)

Cf1634F - Fibonacci Additions

差分好题.

判断数组相等可以用两数组做差解决. 而对于加一个斐波那契数列,可以用差分解决.

斐波那契数列通项公式为 \(f_i=f_{i-1}+f_{i-2}\),所以构造差分数组 \(d_i=c_i-c_{i-2}-c_{i-2}\).

修改的时候直接 \(\rm{O(1)}\) 修改就行了.

At_joisc2019_a - 試験 (Examination)

这题直接三位偏序即可,但还有 \(\rm{O(n\log n)}\) 做法.

考虑 \(x+y\geq z\) 直接二位数点.

\(x+y<z\) 时,可以先数出 \(a+b\geq z\) 的的点,然后减去 \(a<x\)\(b<y\) 的部分即可.

这样写比较麻烦,常数比较大,其实时间和 \(\rm{O(n\log^2n)}\) 差不多.

写三位偏序要注意的是,先处理点再处理询问,因为可能有点和询问相同的情况,若先处理询问则会把这个点漏掉.

Cf1887C - Minimum Array

发现这题要求字典序最小的序列,这是一个很好的性质.

给修改序列(并非原序列)建差分数组,若该序列第一个不为 \(0\) 的数为负数,则字典序更小.

但这个方法只在第一次更新答案时有效. 每次更新后将整个序列清零就行了. 用线段树维护.

其实有用 \(\texttt{set}\) 的更简单的写法,不过我不会(懒得想了).

Lg7312 - [COCI 2018/2019 #2] Sunčanje

介绍一种简单(?的写法.

对于一个矩形 \(r_i\),怎么判断没有被覆盖呢?只要算出在其之后的矩形中与其无交的数量 \(num\).

\(num=n-i\) 则没有被覆盖.

计算与矩形 \(i\) 无交的矩形数量,可见此图.

我们可以算出严格在一条边外的矩形数量,再算出严格在一个角上的矩形数量,然后简单容斥就行了.

时间复杂度 \(\rm{O(n\log^2n)}\),因为要三位数点.

Cf815D - Karen and Cards


假设 \(f_{i,j}\) 为第一张牌为 \(i\),第二张牌为 \(j\) 时可选牌的数量,初始时 \(f_{i,j}=mxc.\)

现在我们有一张牌 \((a,b,c)\),容易得到:

  • 对于 \(i\in [1,a],j\in [1,b],f_{i,j}=0\).
  • 对于 \(i\in [a+1,mxa],j\in [1,b],f_{i,j}=\min(f_{i,j},mxc-c)\).
  • 对于 \(i\in [1,a],j\in [b+1,mxb],f_{i,j}=\min(f_{i,j},mxc-c)\).

转化一下,就是先让前 \(i\) 行和前 \(j\) 列对 \(mxc-c\)\(\min\),然后将矩形 \([a,b]\) 填上零.

具体维护就是每次对一张卡牌,\(x_a=\min(x_a,a),y_b=\min(y_b,b),z_a=\max(z_a,b)\),然后对 \(x\)\(y\) 取后缀 \(\min\),对 \(z\) 取后缀 \(\max\).

对于 \((i,j)\),若 \(z_i\geq j\),则 \(f_{i,j}=0\);否则 \(f_{i,j}=\min(a_i,b_j)\).

但是这样做是 \(\rm{O(n^2)}\) 的,会超时. 怎么办呢?

容易发现 \(x\)\(y\) 这两个数组是单调递增的,所以可以维护一个指针 \(pos\) 满足对于 \(j\in [1,pos-1]\)\(x_i\geq y_j\) 且对于 \(j\in [pos,mxb],x_i<y_j\). 可以发现从第一行到第 \(mxa\) 行,这个 \(pos\) 也是单调递增的.

所以我们可以维护 \(x\) 的前缀和,加上 \(x_i\times (mxb-pos+1)\) 就行了,但是填零怎么处理呢,让 \(k=\max(pos,z_i+1)\),统计答案时用 \(k\) 统计.

Lg10800 - 「CZOI-R1」卡牌

上面那道题的四维版本.

假设 \(f_{i,j,k}\) 为第一张牌为 \(i\),第二张牌为 \(j\) ,第三张牌为 \(k\) 时可选牌的数量,初始时 \(f_{i,j,k}=mx.\)

可以像上一题一样考虑加一张牌 \((a,b,c,d)\) 带来的影响:

  • \((0,0,0) - (a,b,n)\) 这个长方体填上零.
  • \((0,0,0) - (a,n,c)\) 这个长方体填上零.
  • \((0,0,0) - (n,b,c)\) 这个长方体填上零.
  • \(0\sim c\) 层对 \(mx-d\)\(\min\).
  • \(0\sim b\) 列对 \(mx-d\)\(\min\).
  • \(0\sim a\) 行对 \(mx-d\)\(\min\).

我们算出对于每一行,取零的最大列 \(x_i\),以及对于每一层,取零的最大行 \(y_k\) 和取零的最大列 \(z_k\).
对于一个点 \((i,j,k)\),若 \(j\leq x_i,i\leq y_k,j\leq z_k\),则 \(f_{i,j,k}=0\),否则 \(f_{i,j,k}=\min(a_i,b_j,c_k)\).

看起来更加复杂,我们怎么快速维护求值呢?

先一层一层求. 在上一题中,对于每一行,我们求出了第一个满足 \(a_i<b_j\)\(i\).
这次我们把第一个 \(b_j> a_i\) 的列,第一个 \(c_k<a_i\) 的行以及第一个 \(c_k<b_j\) 的列求出来,记作数组 \(f,g,h\).

我们维护被 \(b_j\) 覆盖时,\(b_j\) 的和以及 \(a_i\) 的和,以及被 \(c_k\) 覆盖时, \(c_k\) 的和以及 \(a_i\) 的和,具体过程如下:

从第 \(i-1\) 层到第 \(i\) 层,一定会有 \(y_{i-1}-y_i\) 行取消填零,然后我们对这些行做处理.
对于第 \(j\) 行,做贡献的肯定是 \(k\in (x_j+1,mx]\) 列,首先维护 \(x_j+1\sim f_j-1\)\(b_i\) 的和,然后再维护 \(f_j\sim mx\)\(a_j\) 的和.
最后就是维护被 \(c_i\) 覆盖的部分,具体如下:

  • \(j<g_{i-1}\),则要维护 \(x_j+1\sim mx\)\(a_j\) 的和,否则维护 \(c_i\) 的和,这一部分在上面处理取消填零的时候顺带做处理.
  • 对于 \(j\in [g_{i-1},g_i)\) 这些行,我们单独处理. 若 \(j>y_i\),则维护 \(x_j+1\sim mx\)\(a_j\) 的和,然后取消 \(c_i\) 的覆盖.

最后统计答案的时候,让这些列按是被 \(b_j\) 覆盖还是被 \(c_i\) 覆盖,然后分别求和.

整个过程需要用到四个数据结构维护,维护 \(b_i\) 的和时因为其特殊性(区间加时权值不同),所以用线段树;
维护其他值时可以用区间修改区间查询的树状数组维护,常数较小.

Cf1423G - Growing flowers

见区间推平识 \(\rm{ODT}\).

对于每一种颜色都开一个 \(set\),对一个极长连续空段 \([l,r]\),其对答案的贡献为 \(-(r-l-k+2)\).

我们可以在第一位加长度 \(x\),往后 \(x\) 位每一位加 \(-1\),然后对于一个询问 \(k\),查询 \([1,k]\) 范围内的和就行了.

把这些空段的贡献扔到一个线段树上维护,空段用 \(\rm{ODT}\) 维护就行了.

Lg8512 - [Ynoi Easy Round 2021] TEST_152

将查询区间从左到右扫描线,用一个树状数组记录每个时刻的值,区间推平时肯定有区间被覆盖,减去区间对应时刻的值.

最后用树状数组区间查询就行了.

Bzoj5312 - 冒险

对于整棵线段树,维护区间最大值,区间和(\(\&\))以及区间或(\(|\)).

若操作对整个区间的影响一致(或没有影响),则不继续修改.

具体到实现就是和操作对区间的或无影响,或者或操作对区间的和无影响,或者操作对区间和或影响相同,就不继续修改.

时间复杂度 \(\rm{O(n\log^2n)}\),可以用颜色段均摊分析.

Qoj7980 - 区间切割(集训队互测 2023-2024 Round 17 B)

我们把一个区间分成 \(3\) 份,在前三分之一被切掉的一定是前三分之一,后三分之一同理.

然后找到最先切掉中间二分之一的操作,直接维护即可. 因为每次维护都切掉至少三分之一,所以时间复杂度带 \(\log\).

Cf1749F - Distance to the Path

直接开 \(21\) 个树状数组,修改的时候在对应的 \(d\) 上差分.

询问的时候不断往上跳到 \(d\) 级祖先,询问对应子树,用树状数组和 \(\texttt{dfs}\) 序维护.

但对于 \(\texttt{lca(x,y)}\) 向上的这一部分很难处理,设 \(dp_{i,j}\) 为以 \(i\) 为根距离为 \(j\) 时的贡献,从 \(\texttt{lca}\) 开始暴力向上维护即可,注意要去重. 询问时也要加上 \(dp\) 数组的贡献.

Cf1957F2 - Frequency Mismatch (Hard Version)

非常哈希的一道题.

我们怎么判断路径上的一种颜色的点数量是否相同呢?

随机出每种颜色的权值,然后处理出每个点到根的路径的信息,用主席树维护.

询问的时候利用树上差分的思想就行了.

Cf1967D - Long Way to be Non-decreasing

一眼看出二分答案. 我们怎么写 \(\texttt{check}\) 函数呢?

可以根据 \(b\) 数组画出一个内向基环树森林,容易在 \(\rm{O(1)}\) 复杂度内处理从 \(u\)\(v\) 的变换次数.

于是就可以搞一个指针,从左到右、从小到大地去贪心了.

posted @   nagato__yuki  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示