2021 7.5~7.20日集训总结

Day.1

集训开始的第一天,以数据结构为主体,在之前的基础上进行了不小的扩展。

并查集

启发式合并:一种根据子树大小为基准的合并集合的方式,能够使得“合并集合”操作和“询问”的复杂度降到 O ( l o g n ) O(log n) O(logn)

路径压缩:在只考虑每个点与其根节点的情况下,我们可以将任意一个子树的父亲设置为根节点,使得查询操作降到 O ( 1 ) O(1) O(1)

最小生成树

简单的过了一下基础的kruskal和prim算法,然后就开始讲一些之前闻所未闻的算法

kruskal重构树:在kruskal合并的过程中,将合并的过程新建一个节点,表示两个并查集的“父亲”节点,通过这样的操作,我们就可以用这个节点代表经过不超过某个权值的边的联通块。经过这样的特殊构造就可以满足某些题目的要求。

例如:当题目要求从节点1~v不经过权值超过a的最短路时,经过kruskal重购树的构造后,从节点v向上走的过程中,对应的权值会逐渐变大,也就是说一定会有一个节点其对应的子树是从这个节点出发经过不大于 a 的边能到达的所有点,我们只需要取这里面最短路的最小值即可

树状数组

支持区间查询,单点修改,利用差分进行处理可支持单点查询和区间修改,以及扩展运用:二维树状数组。

ST表

基于倍增思想,对于序列a,构造ST表s[i][j]表 i i i~ i + 2 j i+2^j i+2j这一段的最大值,那么可以得到递推式 s [ i ] [ j ] = m a x ( s [ i ] [ j − 1 ] , s [ i + 2 j − 1 ] [ j − 1 ] ) s[i][j]=max(s[i][j-1],s[i+2^{j-1}][j-1]) s[i][j]=max(s[i][j1],s[i+2j1][j1]),在 O ( n   l o g n ) O(n\ log n) O(n logn)的时间内构造出ST表,查询区间最大值

O(1)计算LCA:用欧拉序将树上问题转化为序列问题,此时对于LCA的查询就变为两个节点欧拉序区间内深度最低的点,也就可以用ST表来维护了。

线段树

基础

ZKW线段树普通的线段树是从根节点从上向下操作,而ZKW线段树可以自下而上从叶节点开始,其常数更低,但不够灵活

动态开点:通常线段树4倍的空间较大,动态开店则是在根据访问去分裂区间。

历史最值问题

对于线段树上一个节点,需要分别维护其具体的信息和其上的标记,我们以节点当前的时间节点来看,我们必然维护有这个
时间之前的历史最小值,但是没有维护的是当前时间点到标记更新这段时间的历史最小值。

为了解决这个问题,我们可以在节点 x 上维护 (mx , hx ),其中 mx 为当前这个节点的最小值,hx 为历史最小值。同时,维护标记 (dx ,sx ),其中 dx 表示所有作用在这个区间上的 ∆ 的总和,sx 表示作用在这个区间上的所有 ∆ 的和的历史最小值。考虑节点 x 的标记 (dx ,sx ) 传递到 y 上,那么我们有
( d y , s y ) → ( d x + d y , m i n s x , d x + s y ) (dy ,sy ) → (dx + dy , min{sx , dx + sy})% (dy,sy)(dx+dy,minsx,dx+sy)

(并未完全看懂)

树链剖分

根据子树大小对于每个节点进行分类,一个节点子树大小最大的那个儿子为重儿子,一个节点与其重儿子的连边为重边,相互之间连接的重边为重链。

进行处理完之后,对于任意一个节点,其向根的路径中最多只会经过 l o g   n log\ n log n条重边,每经过一条轻边,子树大小翻倍,理由如下:

考虑对于任意一个节点 y y y,其父节点为 x x x y y y x x x的轻儿子。此时节点 y y y一定存在一个子树大小至少一样的兄弟节点,也就是说 s i z e x > = s i z e y ∗ 2 size_x>=size_y*2 sizex>=sizey2

这时,我们在构造dfs序时优先访问每个节点的重儿子,就可以满足子树和重链在dfs序列上形成连续的区间

标记永久化

就是对于懒标记不再下传,在进行询问时直接将标记下传到答案上

李超线段树(又一个神奇的东西

简洁的来说,就是在线段树上的每个节点上保存一条线段,统计这个节点所对应区间的直线上的最大值。

每次添加直线时判断这条直线是否对答案有贡献,若有,则进行替换,否则,直接不做修改。

吉司机线段树

与李超线段树思想一致,用于处理类似于“将一个区间所有大于x的数变为x”的操作,记录每个区间的最大值,次大值以及次大值的出现次数,对于每个修改操作进行分类讨论

  • 若最大值小于x,不进行任何操作
  • 若最大值大于x,次大值小于x,则直接更改最大值
  • 若都不满足,则继续向下递归。
感受

第一天还是蛮自闭的,第一次集训开始学会去适应那种学习方式。

Day.2

第二天基于第一天数据结构进行扩展,讲述了可持久化数据结构。

数据结构的可持久化就是将一个数据结构的历史状态全部存储下来,以便快速查找之前出现过的某个操作的结果

主席树(可持久化线段树)

大致思路是每当修改一个节点时,新建一条从根节点到此节点的路径,其他子节点连向上一棵线段树的子节点

线段树合并:直接暴力合并,其复杂度取决于叶节点的总数量,为 O ( m   l o g   n ) O(m\ log \ n) O(m log n)

可持久化数组

基于时间建立数组,在新增元素时开辟新的节点即可。

可持久化并查集

可持久化并查集基于可持久化数组,注意由于路径压缩会导致多次修改从而新建多个节点占用大量空间,所以可持久化并查集多使用启发式合并来实现。

感受

由于以前并未接触过可持久化数据结构,所以对于可持久化数据结构的理解一知半解,还是需要通过代码来具体理解其本质

Day.3

从今天开始的两天都是关于dp的内容,今天主要是两大类dp——树形dp和数位dp

树形dp

顾名思义,树形dp是在树上进行dp,由于树层层递进和没有环的特殊性质,所以树形dp通常用递归来解决。

经典例题:选课:有若干门课,每门课有其学分,每门课有一门先修课或零门先修课,有先修课的必须先学习先修课再学习该课程。

根据题目中“先修课”这一特殊要求,可以看出所有课之间的关系呈树状结构,所有课共同组成一个森林,进行树形dp。

数位dp

一般是问你一个区间内有多少数满足要求,数据范围可能过大,需要依据题目要求对题目中的数拆开成每一位进行dp

Day.4

状压dp

状态压缩dp,是利用二进制的各种性质来表示状态的一种dp方式,状压实际上是枚举每一位的状态,比较暴力,复杂度为 O ( 2 n ) O(2^n) O(2n),但一些题目能够依照题意排除不合法的情况,使枚举的方案数大大减少

dp优化

老师在下午主要结合一些题目讲了优化dp(也有些非dp题目)的几种主要方式

单调队列优化

单调队列优化的本质是通过单调队列的单调性来保证dp时的最优性,及时排除不合法或较劣的决策

单调队列最多被运用在优化多重背包:

复杂度为 O ( n   m   l o g   k ) O(n \ m\ log\ k) O(n m log k)的多重背包dp式为 d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j − k ∗ v [ i ] ] + k ∗ w [ i ] , d p [ i ] [ j ] ) dp[i][j]=max(dp[i-1][j-k*v[i]]+k*w[i],dp[i][j]) dp[i][j]=max(dp[i1][jkv[i]]+kw[i],dp[i][j]),其中 0 < = k < = c [ i ] 0<=k<=c[i] 0<=k<=c[i]。仔细观察可发现对于不同的v[i],每次状态转移只会发生在同一组中,所以上面的dp式可转化为 d p [ i ] [ b + x ∗ v [ i ] ] = m a x ( d p [ i − 1 ] [ b + ( x − k ) ∗ v [ i ] ] + k ∗ w [ i ] , d p [ i ] [ b + x ∗ v [ i ] ] ) dp[i][b+x*v[i]]=max(dp[i-1][b+(x-k)*v[i]]+k*w[i],dp[i][b+x*v[i]]) dp[i][b+xv[i]]=max(dp[i1][b+(xk)v[i

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值