2019 暑期训练 最后一季
6.30 BZOJ 3551 强制在线,问从一个点v出发只走小于等于x的边能到达的第k大的点。利用kruskal重构树,就是在用克鲁斯卡尔求最小生成树的时候新加一个点向合并的两个点连边,这些虚点的点权就是相连两点的边权,因此具有单调性(由kruskal的过程可以知道这一点,子树中的点权一定小于等于该点),所以我们可以用倍增的方式找一下点权小于等于x的最上方的点。然后搞出这颗树的dfs序,建主席树,从而先倍增然后求区间第k大。从而做到在线。离线的话按权值排序,然后在做克鲁斯卡尔的过程中进行平衡树合并(我只会嘴),并完成所有小于等于该边权的所有询问?
7.1 BZOJ 3732 把NOIP2013火车运输直接反了一下,给一张无向图,问从A到B的路径上最长边最小是多少。由MST的构造方式可知,每条边都是当前可选的最小的,所以做完MST时图是连通的且MST中这些边都是最小的,所以满足了最长边最小这一点(其实我也只是大致意会了QAQ,这种最长最小类型的似乎都是用MST搞啊),然后直接就是求LCA然后倍增的时候顺便维护一下最大值即可。原题要注意不连通的情况,在洛谷可以交。然后当然可以用克鲁斯卡尔重构树做,求的就是LCA处这个点的值。
洛谷 P4768 NOI2018 归程。做完3551做的这个。感觉做过3551看这个题目很容易意识到是个克鲁斯卡尔重构树的题,然后这里多了一维海拔,那么就要思考是要用哪个东西来建树,想了20多分钟,感觉还是应该按照海拔建最大生成树,因为要满足单调性。然后我就错了,以为应该先倍增上去然后和1号点用LCA讨论来怎么搞。其实这里按照海拔建树后边权就不单调什么的了。所以应该用dij预处理出每个点的最短路,然后倍增上去直接找祖先这个点的子树的最小值,求最小值可以一遍dfs也可以用线段树把dfs序搞出来然后维护区间最值(PS训练太少,其实我都在走简单方法)。感觉想清楚后挺简单的但写起来出了不少错误。
7.2 BZOJ 3998 这个题就是求给定字符串的子串第K大。后缀自动机一个非常简单也显然的性质是parent树上父亲的right集合的大小可以是儿子的right集合大小的并,其大小也就是该节点所代表的一些串的出现次数。然而,很多资料并没有强调后缀自动机能识别这个串的所有子串,按照字典序的方式。又因为是在线算法,所以我们可以这样脑补这道题的核心dp思想,可以令dp[x]表示某个节点出发能形成的子串个数,dp[x]=1+∑dp[son[x][i]]。因为从x到son[x][i]i]相当于是添加了一个字符i,那么丛x开始,要么不走就是它本身,要么发生这个转移,对于T=1的情况,不同位置的相同子串是不同的,所以是|right|而不是1。然后求第k大,终止条件就是小于等于某一个点的right大小,然后就类似主席树第k大的思路跑一跑就行。半年前的写的时候毫无脑子,根本没有关注问题的本质。这里比较难的地方就是,在后缀自动机上转移到了某一个点并不是说匹配了所有这个点所代表的子串。
7.2 SPOJ LCS/LCS2 多个串的最长公共子串。拿第一个串跑SAM,然后每个串在上面跑,这里的关键是要注意向fa的转移,因为在这里出现过,在fa中一定也有,然后跟该SAM中的点的全局数组取min。最后各个点取最大的值就行。
7.2 HDU4622 只有2000,所以预处理ans[i][j]。跑2000次不同起点的SAM,然后算贡献时我蒙了,其实带来的贡献肯定是新加的点产生的新子串数量,加上len[np]-len[fa[np]]就行。
7.2 BZOJ2882 倍长后字典序最小输出n次。。
7.4 BZOJ5496 感觉是神题啊。表示CF666E写完也只觉得巧妙,可能它是陈年老题的缘故。让我们先来看一看这道12省联考的知乎评价:dls: 能考察选手基本功,一般的垃圾题。这个题我的水平思路是这样的,前面介绍什么基础知识通通是废话,以后再也不看了,然后我们进入正篇,由于是对着sovietpower的博客做题,所以我知道这是个SAM的题。然后开始yy,常规路数肯定是拓扑序dp然后有环就gg吧(发现自己并不怎么会判环),不管,然后继续常规路数,这东西肯定要把串反过来建后缀自动机,这样b对它所有的后代a都是一个可以启发的,然后加上这些A到B的限制,就做完了啊。然后就完全不会做了,这东西有后缀自动机有什么用啊,这么做边数肯定是n^2的,过得了个锤子。于是进入了漫长的自闭环节,然后汪聚聚后来告诉我怎么做了,诶,好像我看得懂他在做什么,但是这是啥啊。半夜手上没有农药,看直播卡的要死,室友明摆着今晚要打lol,于是拿起终极信仰开始刚这题。感觉洛谷那篇的代码真的棒极了,yy了1个多小时,好像明白了奥秘。就是说,其实并不需要连向所有的儿子,首先可以倍增地找到a和b所属的节点,然后这时候每个节点上既有a类串也有b串,所以需要排序,因为b串只能启发以它为后缀的a串,所以按照长度排序,长度相同的时候b串排在a串前。然后就这样从小往大连边,然后每个节点的最后一个b串连向这个节点的孩子(是有点前缀和的味道),这样就变成了拓扑序找最长路,然后并不需要反着连边,当然这里需要想清楚,否则会不对。SAM竟然也能优化建图,真的厉害。感觉SAM很多东西都说不清道不明,比如玄学的暴跳fail竟然是(n*sqrt(n))的。然后666E那样离线也很巧妙。 因为SAM是个在线构造算法,也就是每个前缀都可以找到对应的位置,然后倍增找子串,有一种优美感在其中,但是细节还是很多的,如广义后缀自动机用DFS构造时得复杂度不保证,以及写法的不够精致导致建立的SAM不够规范,表示现在还是不太会BFS式建树。以及在len(q)>len(p)+1时候,siz的域的不复制,这一点我一直没有想明白。每天写题解好累惹。