【笔记】数据结构选讲 2025.2.10

【笔记】数据结构选讲-李雷思问 2025.2.10

Becoder 50751 多重集

G. 多重集 - 数据结构选讲1-李雷思问(day22) - 比赛 - Becoder

通过指定 ac+bcay+by 的大小关系,可以得到一个一维偏序,满足这个一维偏序的时候 max 取到某个值,反之取到另一个值。

在值域线段树上维护这个偏序关系,每次 pushup 的时候统计跨过中点的偏序关系所带来的答案。可以做到 O(qlogq)

P7907 [Ynoi2005] rmscne

定义两个区间 [l1,r1],[l2,r2]“值集合相同”当且仅当 {al1,al1+1,ar1}={al2,al2+1,ar2}

子区间的可能性过多,并不好直接求,我们考虑把选子区间改成:对询问区间 [l,r] 的每一个后缀 [x,r],都维护一个最短的前缀 [x,y] 使得 [x,y],[x,r] 值集合相同,然后记 fx,r=yx+1。然后我们再去找一个最短的后缀 [z,r] 使得 [z,r],[l,r] 值集合相同,我们查询 minlxzfx,r 就好了。核心在于将一个子区间看作某个后缀的前缀。

扫描线从左往右扫 r 维护 fx,r,可以使用线段树维护。找到 z 可以维护所有颜色的最后出现位置的集合在上面 lower_bound 找。总的时间复杂度 O(nlogn)

由于这个复杂度不是本题正解,需要优化常数才能通过。具体是优化找 z 的部分,发现那个集合可以提前加入 [1,n] 所有位置然后每次只做删除操作。可以使用并查集维护。复杂度没有降低(仍然是 O(nlogn),注意),但是却神奇地通过了。

P6773 [NOI2020] 命运

一个 O(n2) 的 dp 可以想一下就能想到,令 fu,j 表示 u 子树中没有被满足的限制(没有已知黑色边的链)的最深链顶的深度,没有这样的链就是 0。转移首先初始化 fu,j=[j=c] 其中 c 是以 u 为链底的最深链顶的深度。紧接着枚举所有儿子 v,如果 (u,v) 染黑则 j 会清零,否则不会动,也就是首先 fv,0 加上 jfv,j,然后做“max 卷积”:

fu,i=max(j,k)=ifu,jfv,k

一种方法是做前缀和之后点乘再差分回来,也可以拆开 max

fu,i=j<i(fu,jfv,i+fu,ifv,j)+fu,ifv,i

最后记得把 jdepufu,j 全部清空,它们已经不合法了。这就是一个 dp。

优化使用线段树合并。合并的时候有一个函数 merge(p, q, l, r) 表示合并 p,q 两个线段树,你再额外传入两个变量 ps,qs 表示 <l 的部分 p 这边的总和与 q 那边的总和。这样如果 p,q 有一个为空的时候,例如 q 是空的,你就需要在 p 上打 ×qs 的乘法标记。叶子的时候,这片叶子的值更新为 valpqs+valqps+valpvalq。其它情况正常递归下去并更新 ps,qs。(所以有可能你需要先合并右子树再合并左子树)

总复杂度 O(nlogn)

[Hangzhou23K] Card Game

如果区间 [l,r] 的答案为 fl,r,那么考虑 l 这边会干出什么事,设 l 右边第一个值与 l 相同的位置是 x。如果 r<x,则 l 只出现一次且不会被其他东西消去,fl,r=fl+1,r+1。否则无论 [l,x] 中间有什么,到了 x 都会消去,fl,r=fx+1,r

不要写可持久化平衡树。直接做线段树合并与分裂就是对的了,因为这里的合并不是“有交并”而是“无交并”,复杂度是固定的 O(logn),而分裂也是 O(logn),因此总的复杂度是 O(nlogn) 的。这个东西带有标记,处理标记的方法参考可持久化文艺平衡树的模板。

UOJ164【清华集训2015】V

一种方法是和 P8868 [NOIP2022] 比赛 一样的矩阵乘法维护信息。另一种方法先忽略了历史最值,将所有操作统一刻画为了 xmax(x+a,b)。由于这个刻画的性质过于好,它的复合与 max 操作都是封闭的,对历史最值的操作也可以用这个刻画进行维护。复杂度 O(mlogn) 乘上一些常数。

LOJ6029 「雅礼集训 2017 Day1」市场

势能线段树。直接说了,这题的势能函数构造是 ϕ(u)=log2max(1,aubu) 其中 au,bu 是线段树 u 节点的最大值、最小值。总势能是所有 ϕ(u) 求和。我们希望一个事情发生:

a/db/d(ab)/d

但是很显然这不是很对,例子是 a=4,b=3,d=2。什么时候这会失效呢?令 a=pd+x,b=qd+y,则其不成立的条件是:

pq>pq+(xy)/dx<y

这个条件看似十分搞笑,实际上也是没什么用(但其实有用),我们通过刚才的推导过程我们得知实际上以下式子是成立的:

a/db/d(ab)/d+1

意思是如果 x<y 会有一个负数出来,我们调整一下它。现在我们最害怕的事情就只有两个:

  1. a=b 的时候,向下递归无法减少势能,这需要区间赋值或区间加标记。
  2. a>b 的时候,势能有一定可能变成 (ab)/d+1,如果这个东西 =ab 我们就完蛋了,例如说 a=b+1(而且 x<y)的时候势能就会不变,例如 ab=2,d=2 而且 x<y 的时候势能也不会变,但你发现没有这种情况。再往上的情况那个 +1 就微乎其微了,因为 ab 总会下降,势能总是能减少的。

那就只有两种情况:

  1. a=b 的时候一定要特判,打标记。
  2. a=b+1,x<yp=q+1,x=0,y=d1 的时候,因为 ab 不变,所以我们打一个区间加的标记,同样的 a=b 的时候也打区间加标记就行了。

每次区间加操作会带来 O(lognlogv) 的势能,每次区间除法操作只会减少势能,总时间复杂度 O(nlogv+qlognlogv)

***这里暂时跳过 segment tree beats 部分

Becoder 29550 牛半仙的妹子序列

总之,这是一个线段树优化 dp 的过程,抛开前面的平凡过程不谈(真的平凡吗?)。总之,我们需要的就是“在线段树区间上,维护出区间内的后缀最值位置上的 fq[i] 之和”。

使用小粉兔线段树,在一个节点上维护区间最大值,后缀最大值的 dp 值之和,以及左子树中 右子树最大值的部分的后缀最大值的 dp 值之和(最后这一个值记作 s)。pushup 的时候只需要确定 s,为此我们拿着右子树最大值(记作 v)进入左子树进行线段树二分,寻找左子树的后缀最大值中最靠右的 v 的值,每次在一个节点上我们就是去看看右子树的最大值(记作 z)和 v 的关系就能往一侧去递归,如果 zv 则要往右子树走,同时说明此时左子树被 z 截断的部分现在也得以保留,我们即刻将那一部分(左子树的 s)统计入当前的 s 中。如此就能计算出 s。最后总复杂度 O(nlog2n)

Becoder 46907 黑白树

先删掉这个改颜色的操作。由于有链加和子树加,我们猜测 dfn 序是跑不了了,而且一个连通块还可以表示为一个大子树扣掉一堆小子树,于是我们大概可以做了,然后发现复杂度有问题在里面。

有人提出了一种算法,以维护白色连通块信息为例,首先将所有黑色点(原文是黑色连通块顶点但我觉得也可以是黑色点)对应的那些子树在线段树上的 dfn 区间对应全都找出来,标记这些线段树节点为灰色,然后我们对白色连通块操作的时候,首先找到顶点(O(logn) 的重链剖分就行),然后对这个顶点的子树进行线段树操作。然后神奇的地方来了,我们 pushdown 和 pushup 的时候,不让标记下传到灰色节点,也不从灰色节点把最值信息上传上来(当然还有普通的区间加要正常下传),这样就控住了白色连通块的范围,至此本题得解,时间复杂度 O(nlogn)

什么你说操作 1 怎么办?让这个灰色区间能动态变化就行,并不难,然后这样修改之后由于标记都已经下传完了所以不再会有问题了。

树上数据结构部分

树上技术总结 - caijianhong - 博客园

posted @   caijianhong  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
历史上的今天:
2023-02-11 题解 LGP9018【[USACO23JAN] Moo Route G】
点击右上角即可分享
微信分享提示