一些杂题记录

abc450_e

他这个字符串拼接的方法相当于从 \(S_3\) 开始前缀确定下来之后便一直不变了。首先把问题转换成差分的形式,即区间 \([1,R]\) 减去 \([1,L-1]\)。然后对于查询考虑递归向下去做,对于 \(S_k\) 一定由 \(S_{k-1}+S_{k-2}\) 组成,我们看查询的地方在前面还是在后面递归下去就好了。然后对于 \(S_1\)\(S_2\) 直接做就好了。

abc450_f

看上去好恐怖。

首先可以不选的边只有那 \(M\) 条,而前面 \(N-1\) 条是一条从后往前指的链,所以只要可以从 \(1\) 走到 \(N\) 就赢麻了。我们记录 \(f_{i,j}\) 表示第 \(i\) 条线段最远走到 \(j\) 的方案数,对于线段的排序我们保证对于满足 \(l_i\le l_j \le r_i \le r_j\)\((i,j)\)\(i\)\(j\) 前面即可。

对于一条线段 \([l_i,r_i]\),显然对于 \(j\in[1,l_i)\cup(r_i,n]\)\(f_{i,j}\gets 2\times f_{i,j}\),因为选不选对答案没有作用。对于 \(j\in[l_i,r_i)\),有 \(f_{i,j}\gets f_{i,j}\),因为选了这条线段就不满足最远能到达的是 \(j\) 了。对于 \(j=r_i\),有 \(f_{i,r_i}\gets f_{i-1,r_i}+\sum_{j=l_i}^{r_i}f_{i-1,j}\),即要么不选这条线段要么在最远能到达 \([l_i,r_i]\) 的区间里面跳过来都可以最远到达 \(r_i\)

这个东西一看就可以用线段树维护那么就做完了。

abc459_f

这啥玩意怎么这么牛。

把严格递增变成单调不降,即 \(a_i \gets a_i - i\)。但是会有负数不妨全体加 \(n\) 那么大小关系不变。

然后我们看前缀和,设原本的前缀和为 \(S\),有 \(S_i=S_{i-1}+a_i\)。对于一次操作过后的前缀和记为 \(S'\),对于操作的 \(i\),在 \(S'\) 只会对 \(S'_i\) 产生影响使得 \(S'_i\gets S'_i-1\)。然后我们就发现操作次数为 \(\sum_{i=1}^{n} S_i-S'_i\),且最后对于每个 \(i\in[1,n]\) 都有 \(S_i\ge S'_i\)

那么对于答案计算就搞定了!

然后呢。

对所以答案要求 \(\sum S'\) 尽可能大。

那我不是直接把 \(S'_i\gets S_i\) 不就好了吗?

你还有要求呢,操作过后的 \(a_i\) 要满足 \(a_i\ge a_{i-1}\) 啊!即 \(S'_i-S'_{i-1}\ge S'_{i-1}-S'_{i-2}\)。因为单位只有 \(1\) 所以这个玩意相当于斜率越来越大,就是一个下凸包。

然后咋办?

保序回归

我们构造一个数组 \(b\) 使得 \(b\)\(a\) 尽可能接近。把每个元素化成若干个单位长度的线段,如果前面的线段的平均值大于当前的就合并。最后会是一个类似单调栈的结构。

然后笨一点的话就把单调栈还原成 \(b\) 然后算前缀和怎么怎么做一下就好了。

难死了!

abc458_f

atcoder 真疯了这能 *1700 的。

看到这么多串串可以建一个 AC 自动机试试,我们发现等同于在 AC 自动机上走 \(N\) 步且没有包含 \(S_i,i\in[1,K]\) 的方案数。记录可达性 \(vis_u\),作为串尾肯定有 \(vis_u\gets 0\)。对于其他的有 \(vis_u \gets vis_u \wedge vis_{fail_u}\)。即能保留的最大的后缀是否能被达到。由于是 bfs 建图所以 \(fail_u\) 的可达性一定已经被更新。

然后就是在 AC 自动机上跑一个倍增的东西,记 \(f_{i,u,v}\)\(u\) 走到 \(v\),走 \(2^i\) 步的方案数,那么有 \(f_{i,u,v}=\sum f_{i-1,u,p} \times f_{i-1,p,v}\)。然后最后答案就是在 \(f\) 上倍增查一下就好了。

abc457_g

首先可以接到苹果 \(i\) 还可以接到苹果 \(j\) 的前提是 \(|X_i-X_j|\le T_j-T_i\),即 \(T_i-T_j\le X_i-X_j \le T_j - T_i\)。转换一下就是:\(X_j-T_j\le X_i-T_i \wedge X_i+T_i \le X_j+T_j\)。这不是二维偏序吗?不对等等。题目要求的是最少的不下降子序列的个数,根据 Dilworth 定理有答案等于最长下降子序列的长度。

abc457_f

哇完全没有思路的 dp。

我们从后往前 dp,记 \(f_{i,j}\) 表示到第 \(i\) 个元素,最大值在 \(j\)

不是哥们你这只有最大值能行吗?

哦还真行。

考虑转移。

  • 对于插入了人非最大值也非次大值的值:

    • 对于 \(d_i=d_{i+1}\),我们可以插入 \((N-i+1)-2=N-i-1\) 个元素到当前位置,相当于每个 \(f_{i,j}\gets f_{i,j}\times (N-i-1),(j\in[1,n])\)
    • 否则你必须动了那么对于摆烂有 \(0\) 种选择所以所有元素清零。
  • 对于插入了最大值,我们有 \(f_{i,i}\gets f_{i,i}+f_{i+1,i+d_i}\)。即 \(i+d_i\) 从最大值变成次大值。

  • 对于插入了次大值,我们有 \(f_{i,i+d_i}\gets f_{i,i+d_i}+f_{i+1,i+d_i}\),即 \(i+d_i\) 还是最大值。

诶还真行。

然后就是一个全局乘单点加单点查了。丢到线段树上就做完了。

abc453_f

考虑如上图构造,给叶子节点带权为 \(1\),求带权后的树的重心。

首先我们叶子节点很金贵!必须在外面有别人才能活,而且只要过重心它就能一次活很多点!!!其次只要叶子节点都能活那大家都能活了!!!哇哦好简单啊那怎么填呢。

我们看这个叶子节点是从哪里下来的(图中的黑色线条的点的部分),记为 \(bel_u\),我们想让一个颜色覆盖尽可能多的 \(bel\) 种类,随便用点什么坐一下就好了。然后就是重心(图中灰点)要注意可能最后一个点只染了最后开的颜色,但是最后开的颜色只用了一次,所以可能要把重心和最后一个点一块儿染。

abc449_f

思维简单代码就不简单。

考虑对于一个黑点 \((x,y)\),会使得 \((i,j),i\in[x-h+1,x],j\in[y-w+1,y]\) 中的点不可以成为一个合法的左上角,然后矩形面积并一下再拿总面积减一下就好了。

CF526F Pudding Monsters

题意:给定一个 \(n\times n\) 棋盘,其中每行每列恰有一个怪物。统计有多少个轴对齐的 \(k\times k\) 正方形区域,其内部恰好包含 \(k\) 个怪物。


首先对于一个 \(k\times k\) 的矩阵里面有恰好 \(k\) 个点,保证每行每列都只有一个点,相当于一个排列满足区间下标为 \([a,a+k-1]\) 的子序列的值恰好覆盖了 \([b,b+k-1]\)

这个要怎么做呢?注意到这个相当于是一个排列,所以每个元素有且仅有一个,那么我们查区间的 \(\max - \min\) 是否等于 \(r-l\) 就好了。那这个又怎么统计呢,我们发现 \(\max-\min\) 是一定大于等于 \(r\) 的,所以我们只需要统计最小值和最小值的个数。这个用一个扫描线和线段树做。\(\max\)\(\min\) 的维护可以是一个单调栈加加减减,然后对于每个位置新加入的时候加入一个 \(l\),统计答案则是看前面值为 \(r\) 的个数。时间复杂度 \(O(n\log n)\)

P7497 四方喝彩

题意:给定一个长度为 \(n\) 的数组,支持区间加、区间乘、区间求和。额外地,可以对一个区间施加持续 \(x\) 次操作的“封锁”,封锁期间该区间不会受到后续区间加和区间乘操作的影响(多个封锁效果可叠加)。


吉老师线段树使用例一则。

注意到区间封锁很难做。咋办呢?我们在线段树上维护一个 \(mn\) 表示这个区间被覆盖的最小层数,然后变成一个类似扫描线的东西,在时刻 \(i\) 覆盖一层 \(1\),在时刻 \(i+k\) 把覆盖消掉。如果 \(mn=0\) 那么一定有孩子没被封锁。我们统计这个点表示的区间的没被封锁的元素个数 \(cnt\),被封锁的元素的和 \(sum_1\),没被封锁的元素和 \(sum_2\),加 tag \(tag_a\),乘 tag \(tag_m\),覆盖层数 tag \(tag_c\)

对于 \(mn\ne 0\) 的区间加和乘,代表区间内全都被覆盖所以不用动,直接返回。

对于 pushup,检查左右儿子的 \(mn\) 的最小值,由于该节点能 pushup 一定有 \(mn=0\),所以一定有儿子 \(mn=0\),从 \(mn=0\) 的地方的 \(sum_1\) 更新上来 \(sum_1\),其他地方更新上来 \(sum_2\),同时维护 \(cnt\) 即可。

对于 pushdown,只修改没被封锁的区间即可,其他就是基础线段树的操作。

代码挺难写。

AT_abc461_e [ABC461E] E-liter

给定一个初始全白的 \(N\times N\) 网格,依次进行若干次操作:将某一整行染成黑色,或将某一整列染成白色。每次操作后输出当前网格中黑色格子的数量。


注意到每次要么填一行黑要么填一列白。

  • 对于填一行黑
    • 相当于问上一次这一行填黑的时间 \(t\) 到现在的时间 \(i\) 有几个地方被填白了,相当于问每一列最后一次涂黑的时间在 \([t,i]\)
  • 对于填一列白和黑分析类似。

最后用两颗树状数组维护一下最后一次的出现时间就好了,时间复杂度 \(O(n\log n)\)

AT_abc461_f [ABC461F] Total Product is N

给定正整数 \(N\),考虑所有元素互不相同且所有元素乘积恰好为 \(N\) 的正整数序列。定义一个序列的权值为其所有元素之和,求所有满足条件序列的权值之和,对 \(998244353\) 取模。


首先 \(10^{10}\) 的因数个数最多只有 \(2500\) 左右个,最多可以拆成不超过 \(14\) 个不同的因数相乘,因为 \(14!>10^{10}\)。其次我们考虑做一个背包一样的东西,用 \(f_{i,s}\) 表示当前积为 \(i\) 个因数,长度为 \(s\)\(g_{i,s}\) 表示方案数,那么我们有 \(f_{ik,s+1}\gets f_{ik,s+1}+f_{k,s}+g_{k,s}\times i\)\(g_{ik,s+1}\gets g_{ik,s+1}+g_{k,s}\)

最后答案是 \(f_{n,s}\times s!\),可是 \(n\) 太大了所以要离散化一下怎么做一下。

P5787 二分图

给定一个动态图,其中每条边只在指定时间区间内存在。对于每个时间点,判断当前图是否为二分图。


考虑一个并查集维护二分图判定的方法,对于 \(u\) 表示 \(u\) 在左部,\(u+n\)\(u\) 在右部。对于一个边 \((u,v)\),如果并查集有 \((u,v)\),那么就寄寄了,否则连 \((u,v+n),(v,u+n)\)

考虑线段树分治,然后可撤销并查集维护一下是否可行就好了。

P4219 [BJOI2014] 大融合

给定若干个初始孤立的点,依次连接两棵不同的树。对于询问边 \((x,y)\),求当前树中有多少条简单路径经过这条边。


对于一个询问相当于删掉 \((x,y)\)\(x\) 所在连通块的大小与 \(y\) 所在连通块的大小的乘积。那么依旧考虑线段树分治,然后用可撤销并查集维护节点大小。

P3292 [SCOI2016] 幸运数字

给定一棵点带权树。对于每次询问 \((x,y)\),考虑路径上所有点权,可以任选其中若干个数进行异或,求能够得到的最大异或值。


对于一个集合求一个数异或集合中若干元素的最大值可以用线性基做,对于树上的路径我们可以用倍增跳 LCA 的方法往上跳的时候顺便合并线性基,然后就好做了。线性基合并有一个 \(\log\),所以时间复杂度是 \(O(n\log n\log V)\),其中 \(V\) 为值域。

P4151 [WC2011] 最大 XOR 和路径

给定一个带非负边权的无向连通图,求从 \(1\)\(N\) 的一条路径(允许重复经过点和边),使路径上所有边权的异或和最大。


由于一条路径可以通过走一个环走回原点获取一个 \(\oplus\) 的值,我们考虑直接拎出一颗生成树,相当于路径是树上一条路径从 \(1\)\(N\) 再走若干个环。为什么呢?因为一个环走完之后就可以消掉原本走的路径而是一个新的路径了。包括不在原本路径上的环也可以走上去转一圈再回来,相当于只在环上转了一圈。

CF938G Shortest Path Queries

给定一个动态连通带权无向图,支持加边、删边和询问。路径长度定义为路径上边权的异或和,询问两点间所有路径(允许重复经过点和边)中异或和最小的路径长度。


动态加边删边考虑线段树分治。对于两棵树上的节点 \((u,v)\) 边权为 \(d\) 的合并,我们可以考虑对于根节点 \(tu\)\(tv\) 进行合并,用并查集启发式合并就可以把合并的时间变成 \(O(\log n)\),但是怎么连边呢?我们考虑 \(u\to tu\) 的边权 \(val_1\)\(v \to tv\) 的边权 \(val_2\),那么相当于可以连一条 \(tu\to tv\) 边权为 \(val_1 \oplus d \oplus val_2\)。相当于要从 \(tu\) 走到 \(tv\) 就是从 \(tu\to u\to v\to t_v\)。然后就难写了一点就做完了,剩下的部分线性基做一下就好了,时间复杂度 \(O(n\log n\log V)\)

CF1114F Please, another Queries on Array?

给定一个数组,支持区间乘法修改,并查询某个区间所有元素乘积的欧拉函数值 \(\varphi\!\left(\prod_{i=l}^{r} a_i\right)\)(结果对 \(10^9+7\) 取模)。


我会单个值的欧拉函数!

对于 \(x=\prod p_i^{k_i}\)\(\varphi(x)=\prod_{i=1}\frac{p_i-1}{p_i}\)

哇塞 \(a\le 300\) 诶,注意到小于等于 \(300\) 的质数只有 \(62\) 个,我们不妨用一个位掩码存 \(p_i\) 在这个区间内是否存在,然后再维护一个乘积就好了!最后按照上面的公式做一下就好了!!时间复杂度 \(O(nP+n\log n)\)\(P\) 为给定范围内质数个数。

P1600 [NOIP 2016 提高组] 天天爱跑步

给定一棵树和若干条路径。每个点 \(j\) 给定一个时间 \(w_j\),求有多少条路径经过该点时,恰好是在出发后的第 \(w_j\) 秒到达该点。


黄点为起点 \(s\),红点为终点 \(t\),蓝点为当前考虑的观测者所在的点 \(x\),绿点为 LCA \(p\),我们考虑两种情况,把 \(x\) 在上行 / 下行进行分类讨论:

  • 蓝点在黄点到绿点之间:

    这种情况我们有黄点到蓝点的时间是 \(dep_s-dep_x\),所以要满足这一条可以被观测到有 \(dep_s-dep_x=w_x\),即 \(dep_s=dep_x+w_x\)

  • 蓝点在绿点到红点的路径上:

    此时黄点到蓝点的路径是 \(dep_s-dep_{p}+dep_x-dep_p\),此时要是满足条件有 \(2\times dep_p-dep_s=w_x-dep_x\)

然后我们发现这个 \(2\times dep_p-dep_s\)\(dep_s\) 都是定值,所以我们直接线段树合并然后做一下就好了。时间复杂度 \(O(n\log n)\)

CF1179C Serge and Dining Room

给定若干菜品价格和学生拥有的钱数。学生依次购买自己能买到的最贵菜品。支持动态修改菜品价格或学生钱数,每次修改后求最终剩下的最贵菜品价格,若不存在则输出 \(-1\)


首先我们可以感受一下,发现学生的顺序不影响答案,那么就好做了。

一个学生会吃掉 \([1,x]\) 中的一个饭菜,我们对这个区间 \(+1\),表示有一个学生在这里等吃的。

一个饭菜会吃掉 \([1,x]\) 中的一个学生,我们对这个区间 \(-1\),表示这个饭菜解决了一个学生。

那么只要找到最右侧的小于 \(0\) 的位置就是最大的没被吃掉的饭菜,因为小于 \(0\) 表示需要被解决的饭菜比能解决的学生多,那么一定会剩下!

CF1093G Multidimensional Queries

给定一个由 \(k(k\le5)\) 维点组成的序列,支持单点修改,并查询区间内任意两点之间曼哈顿距离的最大值。


这个 \(k\le 5\) 很魔怔啊。我们考虑一下曼哈顿距离的最大值是啥。对于二维的两点 \((x_1,y_1),(x_2,y_2)\),曼哈顿距离为:\(\max\left\{\begin{matrix}+ (x_1-x_2) + (y_1-y_2) \\+ (x_1-x_2) - (y_1-y_2) \\- (x_1-x_2) + (y_1-y_2) \\- (x_1-x_2) - (y_1-y_2)\end{matrix}\right.\)。因为是最大值所以可以直接去绝对值然后选最大值。

所以我们考虑维护一个位掩码,第 \(i\) 位是 \(1\) 表示 \(+p_i\)(点 \(p\) 的第 \(i\) 维),否则是 \(-p_i\)。设维护的答案是 \(f\),全集为 \(T\),当前枚举的集合为 \(S\),那么答案就是 \(\max(f_{S}+f_{T \setminus S})\)

CF960F Pathwalks

给定一个有向图,每条边有输入顺序编号和边权。求一条最长路径,使路径上经过的边的编号和边权均严格递增,输出路径长度(边数)。


何意味啊。首先按照顺序做 LIS 就可以满足编号顺序,其次对每个点开一个树状数组表示大小为 \(i\) 结尾的 LIS 长度的最大值。然后相当于是简单的 LIS,对于一个边 \((u,v,d)\),那么设 \(p\)\(u\) 里面小于 \(d\) 的最大值,往 \(v\) 里面插 \(p+1\) 就好了。时间复杂度 \(O(n\log^2n)\)\(n,w\) 同阶。

P5631 最小mex生成树

给定一个带非负边权的连通无向图,求一棵生成树,使其边权集合的 \(\mathrm{mex}\) 最小,并输出该最小值。


首先一个简单的做法是从小到大枚举答案 \(x\),删掉所有边权为 \(x\) 的边,如果最后可以是一棵树那么就赚麻了答案就是 \(x\)

可是这样有很多重复添加的边怎么办呢?

我们考虑分治,对于区间 \([l,r]\),我们将 \([mid+1,r]\) 的边加入进去,递归 \([l,mid]\) 的区间,然后我们撤销掉刚刚加的边,加入 \([l,mid]\) 的边,递归 \([mid+1,r]\) 的区间。如果 \(l=r\) 而且所有点连通了那么就是可行的,答案即为 \(l\)。时间复杂度是一个 \(O(n\log w \log n)\)

P1852 [国家集训队] 跳跳棋

数轴上有三个无区别棋子,每次可选择一个棋子绕另一个棋子跳跃(跳跃后两者距离保持不变)。判断能否从初始状态变为目标状态,若能则求最少操作次数。


首先三元组不区分棋子,所以一次跳棋只会有两种选择:外面往中间跳/中间往外面跳。

设三元组 \((x,y,z),d_1=y-x,d_2=z-y\)

  • 对于第一种:

    • 如果 \(d_1<d_2\),那么只能从左往右跳,因为从右往左跳会跳出去。
    • 如果 \(d_2<d_1\),那么只能从右往左跳。
    • 如果 \(d_1=d_2\),那么就跳不动了。
  • 对于第二种:

    我们发现如果从中间往外跳了,那么就不会再有任何第一种操作了。

    • 如果跳回刚刚跳来的地方,那么就白跳了浪费步数。
    • 如果从另一边跳,一定会跳出去。

那么这个就是一个跳 LCA 的过程,每次从深往浅跳即可,注意判断浅的点在跳跃的路径上的问题。

P13778 「o.OI R2」=+#-

给定初始信心值 \(k\) 和若干题目的要求值 \(c_i\)。可以任意排列题目顺序:当当前信心值恰好等于 \(c_i\) 时做出该题并使信心值加 \(1\),否则信心值减 \(1\)。求最多能做出多少道题。


我们先来观察一些性质。

假设有一个连续段 \([l,r]\),那么只要有够多的容错那么每个点的位置我们都能吃到,最后停留在 \(r+1\) 即可。

我们设我们做对了 \(s\) 题,错了 \(d\) 题,那么有 \(k+s-d=r+1\),即 \(d=k+s-r-1\)。还有 \(s+d\le n\),那么推一下狮子就有 \(s\le\lfloor\frac{n-k+r-1}{2}\rfloor\)

如果最后停留的位置为 \(l\),那么 \([l,top]\) 里的题都可以挑着做,所以 \(s\le\sum_{i=l}^{top}cnt_i\)

计算答案即是找到每个非零连续段 \([l,r]\) 做一下就好了。时间复杂度 \(O(n+V)\),其中 \(V\)\(c_i\) 的值域。

P9992 TEST_130

给定一棵有根树,定义 \(N(w,d)\)\(w\) 的子树内到 \(w\) 距离不超过 \(d\) 的点集。对于每次询问 \((w,d)\),求有多少个形如 \(N(w',d')\) 的集合满足 \(N(w',d')\subseteq N(w,d)\)


首先我们考虑一个节点 \(u\) 为一个节点 \(v\) 的祖先。对于合法的 \(d\),集合 \(N(v,d)\) 一定不重。那么我们考虑一个 \(v\) 的贡献。

\(u\) 能到达的最深的地方为 \(d'\)\(v\) 的子树最深深度为 \(mxdep_v\),那么我们分类讨论:

  • \(dep_v>d'\),那不是纯搞笑吗都到不了,贡献为 \(0\)
  • \(mxdep_v\ge d'\ge dep_v\),那么贡献为 \(d'-dep_v+1\)
  • \(d'>mxdep_v\),贡献为 \(mxdep_v-dep_v+1\)

那么这个东西就是关于 \(d'\) 的分段函数。我们拿一颗 BIT 维护一次函数的斜率,一棵维护一次函数的常数项,一颗维护常函数的贡献。

但是直接把值放进去算还是不对,所以我们在访问 \(u\) 的时候先减去现在的答案,遍历完子树之后出来在加上现在的答案,现在就对了。

P5524 [Ynoi2012] NOIP2015 充满了希望

给定一系列对数组的交换、区间赋值和单点查询操作。对于每次询问 \([l,r]\),从全零数组开始执行第 \(l\) 到第 \(r\) 个操作,求其中所有单点查询结果之和。


二合一?!

首先假设我们在做 \([l,r]\) 的操作,对于一个操作 3 的 \(i\),最后一次的修改时间为 \(t_i\)。只有在 \(t_i\ge l\) 的时候我们才会把第 \(i\) 次查询的答案加进来。所以对于操作我们做区间覆盖/交换两点即可,用棵线段树就好了。

然后后面这个问题就变成了 \(i\le r,t_i>l\) 的点的值的和,那么这个是一个二维数点用树状数组做一下就好了。

CF1009F Dominant Indices

对于每个节点 \(x\),设 \(d_{x,i}\) 为其子树中与 \(x\) 距离恰为 \(i\) 的节点个数。求最小的下标 \(i\),使得 \(d_{x,i}\) 取得最大值。


首先有个很简单的 dp,设 \(f_{u,i}\) 表示点 \(u\) 子树里距离为 \(i\) 的点的个数,显然有转移 \(f_{u,i}=\sum_{v\in son_u}f_{v,i-1}\)。但是暴力转移是 \(O(n^2)\) 的。怎么办呢?

考虑长链剖分,即拎出最长链,那么 \(f_{u,i}\gets f_{v,i-1}\),即 \(f_v\) 直接平移一个单位。剩下的非最长链直接暴力转移。总共的转移复杂度是均摊 \(O(n)\) 的。

P5903 树上 K 级祖先

维护一棵有根树,支持大量树上 \(k\) 级祖先查询。


长剖使用例。

首先先往上跳 \(2^t<k\) 次,随后我们发现根据长剖的性质如果能向上跳 \(2^t\) 次那么长链长度一定大于等于 \(2^t\)。记 \(k'=k-2^t\)\(u\) 为跳了 \(2^t\) 之后的位置,链顶为 \(v\),那么有要在链顶往上跳 \(k-(dep_u-dep_v)\) 步(可为负数)。所以对于每个链顶处理向上/下跳链长的元素分别是多少,这部分空间复杂度均摊为 \(O(n)\)。该算法时间复杂度瓶颈为预处理倍增为一个 \(\log\),最终时间复杂度为 \(O(n\log n+q)\)

AT_agc002_d [AGC002D] Stamp Rally

给定一张无向连通图,每次询问给出 \((x,y,z)\),两人分别从 \(x,y\) 出发,要求总共访问恰好 \(z\) 个不同顶点,求使两人经过边的最大编号最小的方案对应的代价。


首先边权最最值一眼 Kruskal 重构树,考虑建完树之后怎么做。

因为重构树是一个边权随着往上走单调递增的一个东西,很牛。所以我们考虑二分答案 \(V\) 之后往上倍增跳数,直到最后一个点权 \(\le V\) 的点为止。然后 \(u,v\) 两点分别跳到 \(p_u,p_v\),如果 \(p_u=p_v\) 那么能访问的点相当于 \(p_u\) 的大小,否则为 \(p_u\)\(p_v\) 的大小和。时间复杂度 \(O(q\log n\log m)\)

CF1768F Wonderful Jump

给定一个序列,从位置 \(i\) 跳到 \(j(i\le j)\) 的代价为区间最小值乘以距离平方。求从位置 \(1\) 到每个位置的最小总代价。


这题真牛吧。

首先显然的 dp 状态设计是 \(f_i\) 表示跳到 \(i\) 的最小代价。有 \(f_i\gets+\infty,(i\ne 1),f_1=0\)

首先是两个性质:

  1. 如果有 \(i\to j\),假设只有一个严格最小值,那么直接跳不如在中间跳到最小值 \(V\) 的位置 \(k\) 中转在跳过去,前者代价为 \((j-i)^2\times V\),后者为 \(((k-i)^2+(j-k)^2)\times V=(j^2-i^2)V<(j-i)^2V\)。那么,区间有多个最小值,不如把所有最小值跳满然后跳过去。这样就是最优的。
  2. 对于一个最小值 \(a_i\),有 \(j\to i\) 直接跳的权值尽可能小,那么这部分的权值是 \((i-j)^2a_i\)。如果一步一步跳的话,那么由于 \(a_k\le n,(k\in[1,n])\),这样跳的权值最大是 \(n\times (i-j)\)。令 \(i-j=d\),那么使用一次跳到指定地点有可能是最优的情况,就有 \(a_i\times d^2\le n\times d\),即 \(d \le \lfloor \frac{n}{a_i}\rfloor\)

有了这些性质然后呢?性质 2 有一个 \(\lfloor \frac{n}{a_i}\rfloor\) 的东西,所以直接考虑根号分治。

对于 \(a_i> \sqrt{n}\) 的,\(d\le \sqrt{n}\),那么直接枚举可能的 \(j\) 即可,这部分时间复杂度 \(O(n\sqrt{n})\)

对于 \(a_i\le \sqrt{n}\),有对于每个数,作为区间内的严格最小值,对于一种数转移数只有 \(O(n)\) 次。这部分时间复杂度是 \(O(n\sqrt{n})\)

CF600E Lomsat gelral

给定一棵有根树及每个节点的颜色。对于每个节点,求其子树内出现次数最多的所有颜色编号之和。


好看的 DSU on Tree!

我们考虑只用 \(O(1)\) 个数组记录所有信息,并且启发式合并的时候把轻儿子合并到重儿子里面去。所以我们先预处理出每个节点的大小 \(siz\),包含的子树的 dfn 的左右端点和重儿子。然后第二次 dfs 考虑对于轻儿子不存在数组里面重儿子存在数组里面,扫完上来把自己加进去之后把轻儿子全都加进去计算答案。这样的时间复杂度是 \(O(n\log n)\)

CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

给定一棵边带字母的有根树。对于每个节点,求其子树内路径字母可重排为回文串的最长简单路径长度。


因为可以重排,考虑回文串的成立条件。如果长为偶数那么所有东西都出现了偶数次,如果长为奇数那么有且仅有一个字母出现了奇数次。因为字母表只有 \(V=22\),我们还只关心奇偶性,所以我们考虑用一个位掩码给他放进去。记 \(val_u\) 表示根节点到 \(u\) 的位掩码,那么对于 \(u\to v\) 位掩码相当于 \(val_u\oplus val_v\)。然后就是启发式合并的简单套路了。

P5290 [十二省联考 2019] 春节十二响

给定一棵有根树,每个节点有一个权值。需要将所有节点划分到若干个内存段中,使得同一内存段内任意两个节点都不存在祖先—后代关系;每个内存段的代价为其中节点权值的最大值。求所有内存段代价之和的最小值。


原问题等价于两个数组 \(a,b\) 合并,一个 \(a_i\) 只能被至多一个 \(b_j\) checkmax,问最后 \(\sum a\) 的最小值,对于合并应该有将 \(a,b\) 从大到小排序之后 \(a_i=\max(a_i,b_i)\)。这部分的证明可以把 \(a_1\)\(b_i\) 匹配,\(a_j\)\(b_1\) 匹配,然后调整法可得证。

那么我们就会做链上的情况了。树上相当于很多链一起合并。那么这部分用启发式合并做一下,然后每个点存一个大根堆合并一下就好了!

CF1083C Max Mex

给定一棵有根树,每个节点对应一个 \(0\sim n-1\) 的排列值。支持两种操作:交换两个节点上的排列值;询问树上所有简单路径中,路径上排列值集合的 \(\operatorname{MEX}\) 的最大值。


由于是个排列,我们考虑对于每个值 \(v\) 记录节点位置,然后发现两条路径是可以合并的,那么考虑线段树维护这个东西。对于一个区间 \([L,R]\),我们考虑记录左右端点 \(p_1,q_1\)。合并则是如果两条链可以连起来,那么一定有两个点 \(u,v\) 对于剩下两个点 \(w,p\) 均有 \(dis(u,w/p)+dis(w/p,v)=dis(u,v)\)。枚举 \(\binom{4}{2}=6\) 次即可完成合并。那么这个就好做了,然后要考虑写一个单词查询 \(O(1)\) 的欧拉序求 LCA。随后答案就是线段树上二分。考虑记录当前路径端点,二分时考虑合并左儿子,如果可行那么向右递归,否则不合并并递归左儿子。时间复杂度 \(O(n\log n)\)

posted @ 2026-05-29 14:26  coding_goat_qwq  阅读(14)  评论(0)    收藏  举报