2月做题记录
✩ trick
✯ 会大部分,要\(tj\)提示
✬ 会小部分/完全没想到,看了\(tj\)才会
◈ 脑电波
✡ 有某一算法的神秘通用性质
⊗ 待补
- 2月做题记录
- 字符串
- CF1827C
- CF1913F
- P10716
- P11150 ✩✯
- 树
- [NOI2021] 轻重边
- 做法1 ✩
- 做法2
- 做法3 ✡
- 《简单树剖练习题》
- [QOJ9638] 线段树与区间加
- 做法1
- 做法2
- 「GLR-R3」谷雨
- [集训队互测] 数据结构
- [CF1930H]Interactive Mex Tree ✯✡
- [NOI2021] 轻重边
字符串
CF1827C
对于偶回文串,若它有一个偶的回文后缀,那么这个偶回文串一定能拆成若干个偶回文串
那么对于一个好的串的划分,采取能划分就划分的方式,则是唯一的
所以对于每个后缀找到最小的回文后缀即可
用\(PAM\)即可\(O(N)\)解决问题
CF1913F
考虑改变\(s_i\)的字符,消失的回文串是不以\(i\)为中心,且包含了\(i\)的回文串,这个好算的
考虑改变后的,增加的也是不以\(i\)为中心且包含\(i\)的回文串
可以最开始先处理一下,枚举回文中心\(p\),可以很轻松的找到以\(p\)为o中心的最长回文串的长度,此时不能再长,要么是碰到边界了,要么当前两端的点的字符不相同,此时只需要改变其中一个变成另一个即可,我们假设它们已经相同,然后再继续延伸向两侧
复杂度\(O(NlogN)\)
P10716
对于\(k\)的限制,就是限制了\(|A|\)的最大长度,再加上\(A\)必须是\(border\),后面可以\(kmp\)+\(st\)表跳
前面这个是\(check\)是否串\(A\)在\(S\)中贪心的匹配后,第\(k\)个匹配到的串全都包含在\(i\)内,因为一共匹配到的位置只有\(\sum\frac ni=O(NlogN)\),所以可以暴力的找到所有匹配的位置
具体的过程类似链表维护,维护当前点的后一个点,显然可以并查集辅助
复杂度\(O(NlogN\alpha(N))\)
P11150 ✩✯
要求\(S[1,i]+T+S[i+1,n]\)最小,暴力的想法就是枚举所有的\(i\)然后挨个判断大小,但这样复杂度高达\(O(TN)\),似了
考虑去掉无用的\(i\),对于点对\((i,j)\),若满足\(i+j\)最小且\(S[1,i]+T[1,j]<S[1,i+j]\),则显然这里的\(i\)可能成为答案的\(i\),否则当且仅当,前面得到的可能成为答案的\(i\)满足\(S[i-m+1,i]=T[1,j]\),即可置换一下\(S[i-m+1,i]\)和\(T[1,j]\)的位置
因此可以在\(S\)后面塞个\(INF\)
可以\(SAM\)然后枚举\(j\)找最小的\(i\)即可,此时候选的\(i\)的数量级就是\(O(M)\)的了,可接受直接比较了
对于\((i_1,j_1)\)与\((i_2,j_2)\)(\(i_1<i_2\)),有\(S[1,i_1]+T[1,j_1-1]=S[1,i_2]+T[1,j_2-1]\),只需要考虑\(T[j_1,m]+S[i_1+1,n]\)和\(T[j_2,m]+S[i_2+1,n]\)的大小即可,且可以发现,如果\(T[j_1,m]\)是\(T[j_2,m]\)的前缀,那么其实\(T[j_1,m]+S[i_1+1,n]\)就和\(T[j_2,m]+S[i_2+1,n]\)相同了
求出可能是答案的\(i\)后,再往前跳\(T\)的循环即可
视\(N\)、\(Q\)同阶,复杂度\(O(Nlog N)\)
树
[NOI2021] 轻重边
做法1 ✩
比较巧妙的做法,给每个点赋值,然后一条边是重边当且仅当其相连的两点的权值相同
做法2
称题目的重边为标记边
先轻重链剖分,我们维护重链上的信息,轻链的把信息挂到父亲上,即记录一个点的孩子的轻边中,哪些是被标记的边,显然至多俩
那么跳\(a\rightarrow b\)时,因为与路径上的点相连且不在路进上的边中,只有\(O(logN)\)条重链,所以直接去修改这些重链
做法3 ✡
用毛毛虫,然后\(0/1\)表示\(x\rightarrow fa_x\)是否是重边
复杂度都是\(O(Nlog^2N)\)
《简单树剖练习题》
路径上的点的权值的变化就是\(2k|a_u-a_v|^m\),对于与路径相邻的那些重边,\(O(logN)\)条,直接暴力的改,轻边查询的时候暴力的查即可
复杂度\(O(Nlog^2N)\)
[QOJ9638] 线段树与区间加
做法1
其实\(va\)没用,因为\(a_i\)等价于\(\sum_{j\in tree_i} tag_j\times len_j\),那么给\(vb_i\)加上 所有祖先的\(va\)之和乘\(len_i\) 即可
发现操作就形如两条链,一个整体向左,一个整体向右,然后这两条链上的点除了最后一个,都要下传标记,且与链上的点(除了底部那个)相邻的点和链的底部的点都要打上\(k\)的\(tag\)
树剖一下
这个打标记,对于重链头,就可以标记给它的父亲,后面遍历到它的时候再传下来即可,注意帮左/右儿子打的标记要分别记录
考虑怎么维护下传标记,实际上可以直接找到所有标记点然后传下去即可,因为你注意到每次实际上真正打到点上的标记是\(O(1)\)个
复杂度\(O(Nlog^2N)\)
做法2
同样还是只保留\(vb\)
考虑每次\(pushdown(x)\)后答案的变化为\(lazy_x\times(-vb_x+vb_{ls_x}+vb_{rs_x})\),把\(vb'_x\)赋值为\(-vb_x+vb_{ls_x}+vb_{rs_x}\),记\(lazy'\)为\(x\)到根的\(lazy\)之和,那么\(\Delta=\sum_{i\in S}lazy'_i\times vb'_i\),\(S\)表示要下传标记的集合
那么给一个点的\(lazy_x\)加上\(k\)的贡献就是\(k\times vb_x\),在每次操作中,只要找到所有打标记的点的\(vb_x\)之和即可,这个是好记录的,就像做法1一样,记录点\(u\)到其所属链底的所有点的非链上的左/右儿子的\(vb_x\)之和即可
对于每次操作,就是把完全被包含于\([l,r]\)的区间的\(lazy'\)都加上\(k\),与\([l,r]\)有交的区间的\(lazy'\)都清空且加入\(S\),后面这个是两个链,树剖很好维护
对于前面这个,注意到这样的点就是后面那俩链上的点的,不在链上的右/左儿子子树,考虑这样标号,对于一条重链,先把它链上的点都遍历了,再依次遍历其所有的左子树,再一次遍历其所有的右子树,这样就可以表示为一个区间了
复杂度\(O(Nlog^2N)\)
「GLR-R3」谷雨
用毛毛虫,但是端点处的点要特殊处理一下
复杂度\(O(Nlog^2N)\)
[集训队互测] 数据结构
毛毛虫升级版,也许可以叫猫猫虫
先标号一条重链,再依次标号距离该链长度为\(1\),\(2\),\(3\)的点即可
复杂度\(O(Nlog^2N)\)
[CF1930H]Interactive Mex Tree ✯✡
令\(p_1\)是入栈顺序,\(p_2\)是出栈顺序,而\(mex(S)=min(U-S)\),则只需要得到所有不在路径\(x-y\)上的点的值的\(\min\)即可,设\(lca(x,y)=z\),\(x'\)、\(y'\)分别表示\(x\)和\(y\)处于\(z\)的哪个子树中,则\(U-S\)可以表示为:
- \(p_{1,1\sim in[z]-1}\)
- \(p_{1,in[y]+1\sim n}\)
- \(p_{2,1\sim out[x]-1}\)
- \(p_{1,in[x]+1\sim in[y']-1}\)
- \(p_{2,out[x']+1\sim out[y]-1}\)