DS 题杂烩

因为被 NOIP2024T4 吊打了,所以决定练一些 DS 题。

[Ynoi2006] rldcot

区间 LCA 颜色数。

考虑一个能成为答案的 \(x\),要么有 \(x\in[l,r]\),要么存在其不同子树内的两个点 \(u,v\) 都在 \([l,r]\) 内。

注意到一个极小的 \((u,v)\) 才是有用的,即如果存在 \(u',v'\) 使 \(u<u'<v'<v\) 那么就可以把 \(u,v\) 踢掉了。

因此可以 DSU on tree,对每个轻子树内的节点找到前驱后继,显然这样的数对个数是 \(O(n\log n)\) 的,然后就扫描线数颜色就可以了。

[Ynoi2011] 成都七中

查询只保留 \([l,r]\) 的点后,\(x\) 所在的连通块的颜色数。

棘手的部分在于如何刻画「连通块」,考虑转化为 \(\{p|\mathrm{path}(p,x)\subseteq [l,r]\}\),因此只需要关注 \(\mathrm{path}(p,x)\) 中的最小值与最大值。——这样我们就把棘手的「连通块」转化为了路径问题。

这很点分治,所以考虑点分治。

点分治其实有一个很好的性质,就是对于任意一个连通块总存在连通块内的一个点使其在点分树中的子树包含一整个连通块,其实这个点就是连通块内所有点在点分树上的 LCA。证明是 trival 的。

所以可以在点分树上跳 \(x\) 的祖先,然后找到这个点,容易发现它就是点分数上深度最小的在连通块上的点,设为 \(p\)

然后你发现此时所有连通块的点就是 \(\{q|\mathrm{path}(p,q)\subseteq [l,r]\}\),离线之后扫描线数颜色就可以了跟上一题一模一样啊话说这题真的有黑吗

[Ynoi2018] 末日时在做什么?有没有空?可以来拯救吗?

著名臭名昭著

区间加 \(x\),询问区间最大子段和。

说句闲话,如果保证 \(x>0\) 可以用 KTT 在线做。

记最大子段和为 \(mis\),最大前缀和为 \(mps\),最大后缀和为 \(mss\),区间和为 \(sum\)
于是众所周知 \(mis=\max(mis_0,mis_1,mss_0+mps_1)\)

考虑线段树,那么我们需要实现一个懒标记的区间快速更新,如果 \(x>0\) 就可以 KTT 了,但是这道题不行。

有一个比较直接的想法,就是对区间转而维护长度为 \(i\) 的最大子段和,记作 \(mis_i\)。这样就可以快速得到区间 \(+x\) 后的答案了。则 \(mis_i=\max(mis_{0,i},mis_{1,i},\max_{0\le j\le i}\{mss_{0,j}+mps_{1,i-j}\})\)

发现形如一个极大加卷积的形式,故考虑闵可夫斯基和,即对 \(mps\)\(mss\) 建凸包,对于 \(mis\) 也建凸包,这样每次查询加 \(x\) 后的结果就直接用这条斜线切一下就可以了。

可是这样每次从子儿子更新的时间就变成了 \(O(n)\) 了,怎么办呢?

回想一下过去我们对于这样的问题是如何处理的,譬如区间数颜色,它的复杂度也是这个样子,我们使用了分块的手段,因此这道题也考虑分块。

与区间数颜色不同的是,区间颜色数可以快速地更新信息,而这道题的区间最大子段和只能通过分治的方法处理,因此不能单纯的只用分块,所以可以对每个块建一棵线段树。

  • 整块修改:打标记。
  • 散块修改:如刚才所言,在线段树上线性 \(O(\sqrt n)\)
  • 查询时随便合并一下区间内所有块的信息就可以了。散块的信息在线段树上同样线性 \(O(\sqrt n)\) 得到。

时间复杂度 \(O((n+q)\sqrt n)\),但是空间复杂度 \(O(n\sqrt n\log n)\) 爆炸。

注意到这道题不要求强制在线,所以可以逐块处理优化空间。

这道题细节还是太多了,已经调了一个星期了,还是有生之年再调吧

[WC2022]秃子酋长

\(O(n\sqrt n\log n)\) 是简单的,注意到如果只进行删除操作,就可以用链表维护平衡树。

所以可以用不插莫队,跟不删莫队差不多。

[十二省联考 2019] 希望

问有多少个由 \(k\) 个树上连通块组成的集合,使存在这 \(k\) 个连通块的交集中的某个点到这 \(k\) 个连通块中的所有点的距离都不大于 \(L\)

显然子树的交集还是子树。所以可以用点边容斥,即统计对所有点满足条件的方案数之和减去对所有边使其两个端点都同时满足条件的方案数之和。

显然不同的连通块直接互不干扰,因此我们只需要算出来选一个连通块的方案数,最后取 \(k\) 次方即可。

考虑树形 DP,设 \(f_{i,j}\) 表示在 \(i\) 的子树内距离不大于 \(j\) 的点中选一个连通块的方案数,则有 \(f_{u,j}=\prod_{v\in \mathrm{son}_u} (f_{v,j-1}+1)\);设 \(g_{i,j}\) 表示在 \(i\) 的子树外距离不大于 \(j\) 的点中选一个连通块的方案数(要求 \(i\) 的父亲必选),则有 \(g_{u,j}=(g_{\mathrm{fa}_u,j-1}+1)\times\prod_{v\in \mathrm{bro}_u}(f_{v,j-2}+1)\)

最终点的贡献为 \(\sum_i (f_{i,L}\times (g_{i,L}+1))^k\),边的贡献为 \(\sum_i (f_{i,L-1}\times g_{i,L})^k\),答案就是这两个东西的差。

这样我们就可以做两遍 DFS 算出 \(f\)\(g\),时间复杂度 \(O(NL)\)

观察到 DP 状态中有一维深度,考虑长链剖分优化。

说白了就一句话:长儿子继承,短儿子暴力合并。

这里为了方便继承,可以令 \(f\gets f+1,g\gets g+1\),然后就是 \(f_{u,j}=\prod_{v\in \mathrm{son}_u}f_{v,j-1}+1\)\(g_{u,j}=g_{\mathrm{fa}_u,j-1}\prod_{v\in\mathrm{bro}_u}f_{v,j-2}+1\),然后你发现从短儿子那儿更新完之后需要给整条长链的 \(f\) 给加个 \(1\),可以打一个加法标记。

但是有一个问题,因为我们状态定义的是距离不大于 \(j\),因此其实 \((len_u,+\infin)\) 都是有值的,且都等于 \(f_{u,len_u}\),但是我们又不能暴力更新,否则会影响复杂度。这时打一个乘法标记就可以了。

这时 \(g\) 你不能再两遍 DFS 算了。因为长链剖分的内存是共用的,你只能在线地求出 \(g_{u,L}\)

首先 \(g_{u,j}\) 显然等于 \(g_{\mathrm{fa}_u,j-1}\dfrac{f_{\mathrm{fa}_u,j-1}-1}{f_{u,j-2}}+1\),但是如果 \(f_{u,j-2}\equiv 0\) 就寄掉了。所以可以用前缀积乘后缀积的形式。

[BJWC2018] Border 的四种求法

不是正解

闲话:是自己想出来的非正解。刚想 @管理员 放题解,就发现评论区已经有人发表了。

你发现区间求 Border 等价于找到最小的 \(i\in(l,r]\) 满足 \(LCP(suf_l,suf_i)\ge r-i+1\),而使用 SA 就有 \(LCP(suf_l,suf_i)=\min_{k\in[rk_l,rk_i)\cup[rk_i,rk_l)}h_k\)

然后可以用「启发式分裂」,本质上是笛卡尔树上启发式合并。

枚举 \(l\) 统计答案,不难发现一个 std::set<int>.lower_bound 就解决了。

枚举 \(i\) 统计答案,你发现形如一个三维偏序,扫描线之后树套树/KD树做,时间复杂度 \(O(n\log^2n)\)

也不是正解

SA 可以求出 LCP,而 SAM 的 parent 树(本质上是反串的后缀树)可以求出 LCS。

具体的,两个子串的 LCS 就是它们 parent 树上的 LCA。

于是,我们就是找到一个最大的 \(i\in[l,r)\) 使得 \(LCS(pre_i,pre_r)\ge i-l+1\),而 \(LCS(pre_i,pre_r)=len_{LCA(i,r)}\)

依然可以树上启发式合并做到 \(O(n\log^2n)\)

正解

暂时没看懂而且也不属于 DS 的范畴

posted @ 2024-12-04 17:48  justalearner  阅读(71)  评论(0)    收藏  举报