DS 合集
Problem A. P5314 [Ynoi2011] ODT
题意:
给定一棵树,树有点权,要求支持路径加,查询一个点的距离小于等于 \(1\) 的邻域的 \(k\) 小点权。
\(1 \leq n, m \leq 10^6\),\(3\) 秒,\(500\) MB。
解法:
小清新树剖题。
对于这类看似无从下手的树上问题,考虑树剖可能是一个很好的手段。
先将路径加改为到根路径加,树剖的很好性质是到根路径总会被分为 \(O(\log n)\) 条重链。于是一个自然的想法就出来了。对于每个点使用平衡树维护除了其重儿子和父亲外的点权。询问时重新插入即可。现在到根路径加只需要在轻重链改变时重构一下。同时要维护路径加单点求值,用树状数组维护即可。总复杂度 \(O(n \log^2 n)\),可以通过。
Problem B. P5311 [Ynoi2011] 成都七中
题意:
给你一棵 \(n\) 个节点的树,每个节点有一种颜色,有 \(m\) 次查询操作。
查询操作给定参数 \(l\ r\ x\),需输出:
将树中编号在 \([l,r]\) 内的所有节点保留,\(x\) 所在连通块中颜色种类数。
每次查询操作独立。
\(1 \leq n, m, col \leq 10^5\),\(l \leq x \leq r\)。时限 \(1\) 秒。
解法:
好题。
考虑 \(x\) 所在连通块的点,其充要条件为到 \(x\) 的路径上的点的最小值和最大值都在 \([l,r]\) 内。
这里有一个很显然的东西,设对 \(l,r,x\) 询问答案为 \(f(l,r,x)\),我们发现对于任意一个和 \(x\) 连通的 \(y\),都有 \(f(l,r,x)=f(l,r,y)\),如果我们能方便的找到某个 \(y\),且这个 \(y\) 的答案便于计算,那就好办了。
统计关于一个端点为 \(x\) 的路径时,一个套路是在点分树上考虑。发现我们如果找到最浅的 \(x\) 在点分树上的祖先 \(y\),使得 \(y\) 与 \(x\) 是连通的,那么连通块其余点必然在点分树中 \(y\) 子树内。这个性质并不十分显然。如果存在某个 \(y\) 子树外的点和 \(x\) 连通,那么 \(x\) 必然和 \(x,y\) 在点分树上 LCA 连通,这个 LCA 必然在 \(y\) 之上,和 \(y\) 的最浅性不符。
对于每个询问找到 \(y\),之后的事情就容易了。将询问挂到 \(y\) 上面,然后对于每个 \(y\),对 \(y\) 子树内的点到 \(y\) 的路径的最小值和最大值统计答案,只需要简单的扫描线。总复杂度 \(O(n \log^2 n)\),可以通过。
Problem C. P7126 [Ynoi2008] rdCcot
题意:
给定一棵 \(n\) 个点的树,无边权。再给定一个常数 \(C\),构造一个 \(n\) 个点的无向图,\((u,v)\) 连边当且仅当树上距离 \(dis(u,v) \leq C\)。
\(q\) 次询问,每次给定 \(l,r\),求只保留图上 \([l,r]\) 内的点和边,图的连通块数量是多少。
解法:
很牛的一个题。
一个想法是,对连通块计数是困难的,但是如果能对于连通块对应成某个东西,对这个东西计数是容易的,题就做完了。
考虑对于每个连通块,找一个点代表整个连通块。这个点对于每个连通块是存在且唯一的。如果这样的点容易刻画性质,那么之后就好做了。
事实上,对于每个连通块,取 BFS 序最小的点作为代表元即可。对于非代表元点,可以说明连通块中必然存在一个点,BFS 序比其小且和其有直接连边。证明考虑每个非代表元,必然存在一条路径和代表元连通,如果这条路径长度为 \(1\) 则证毕,否则可以归纳证明。
于是问题转化为求区间中有多少点,满足不存在区间中的其余任何一个点满足 BFS 序小于他,且有直接连边。
考虑处理出 \(pre_i\) 和 \(nxt_i\) 表示编号 \(i\) 前最大的 BFS 小于 \(i\) 的 BFS 序,且距离符合条件的点。\(nxt\) 同理。求出后,即询问区间 \([l,r]\) 中有多少 \(i\) 满足 \(pre_i < l\) 且 \(nxt_i > r\)。这一部分直接数全局的,然后减去两边的,做三次离线扫描线即可。
如何求出 \(pre\) 和 \(nxt\) 呢?考虑点分治。很好的一点是这里的点分治不需要消除子树内的影响。于是对于每个分治重心将所有点拉出来按照 BFS 序做扫描线,线段树上二分即可。总复杂度 \(O(n \log^2 n + m\log n)\)。
Problem D. P7124 [Ynoi2008] stcm
题意:
你要对于一棵树维护一个点集,支持插入和撤销。你需要在 \(O(n \log n)\) 的插入次数内维护出每个点的子树补集。即你需要对于每个点,存在某个时刻,集合是这个点子树补集。
具体来说,\(n \leq 10^5\),你的插入次数不能超过 \(4.5 \times 10^6\)。
解法;
做法很多,但有一个十分厉害的分治做法。
考虑 DFS 序,每个点子树对应一个区间,那么子树补相当于前缀加后缀。
考虑直接在 DFS 序上分治,递归到 \([l,r]\) 内,满足已经加入 DFS 序在 \([1,l)\) 和 \((r,n]\) 中的点。对于包含于左右子区间的,插入后,递归处理,然后撤销。对于横跨中间的点,考虑扫描左端点从 \(l\) 到 \(mid\),并将右端点移动维护所有要求区间。注意到 DFS 序的极强性质是任何两个子树区间要么不交要么包含,所以指针移动次数必然是对的。
这个做法拓展性很强。对于维护树上子树补的相关问题,大多都可以用这个做法维护。
Problem E. 区间虚树边集大小
题意:
给定一棵树,不带边权,\(q\) 次询问对区间 \([l,r]\) 建虚树,虚树边权和是多少。
解法:
这个其实是比较简单的。
不妨认为每次建立虚树都将根,即 \(1\) 号点一起建立虚树。多余的边权其实是 \(1\) 到这些点的 LCA 的路径。多出来的部分简单 RMQ 就能处理。
接下来考虑每条边,其在虚树上等价于子树内存在关键点。冷静下来思考一会,这是不是太经典了!对着 \(r\) 扫描线,维护每条边最后一次被覆盖位置,相当于询问全局 \(\geq l\) 的边数量。树剖上套个颜色均摊段,就做到了 \(O(n \log^2 n)\) 了。
Problem F. 树上邻域数颜色
题意:
给定一棵树,无边权,点有颜色。\(q\) 次询问某个点 \(u\) 距离 \(\leq d\) 的邻域颜色数。
解法:
乍一看很困难啊!
考虑你需要怎么维护颜色数。对于每种颜色,选一个离 \(u\) 距离最小的点进行贡献,距离相等随便找一个顺序,比如按照编号。
现在考虑每个点能贡献到哪些点。对每种颜色建立虚树,发现虚树上每条边上,离这个点距离最近的关键点总是一段前缀和一段后缀。首先容易确定对于每个虚树上的点,最近关键点在哪。这部分应该可以 DP 或者直接以关键点为起点跑最短路。然后每条边的前缀后缀切换点是容易求出的。那么每条虚树边上,对于某个关键点的贡献可以被拆成子树减子树,也就是两个 DFS 序区间。所以每个点影响的位置是 \(O(1)\) 个 DFS 序区间。现在按照询问点的 DFS 序做离线扫描线,你要做的就变成了单点修改邻域求和。直接点分树维护就可以做到两个 \(\log\)。
Problem G. CF765F Souvenirs
题意:
给定 \(n\) 个非负整数 \(a_1,a_2,\cdots,a_n\) 和 \(q\) 次询问。每次给定 \(l,r\),在第 \(l\) 个数到第 \(r\) 个数中选两个下标不同的,最小化两数差的绝对值。你只需要输出最小的差的绝对值。
\(n \leq 10^5\),\(q \leq 3 \times 10^5\),\(0 \leq a_i \leq 10^9\)。
解法:
对于很多这种在一个区间中选两个数并最优化某个东西的题,一个思考方向是是考虑真正有用的元素对 \((i,j)\) 有哪些。
比如对于这个题,确定 \(i\) 之后,一个显然的想法是对于所有有用对 \((i,j)\),则对于所有 \(i<k<j\),要么 \(a_k\) 都大于 \(\max\{a_i,a_j\}\),或者所有 \(a_k\) 都小于 \(\min\{a_i,a_j\}\)。
这玩意不太行啊,因为有用对还是太多了。能不能给力一点?考虑对于 \(i\),不妨设找到了某个 \(a_j \geq a_i\),根据上面这个结论,下个 \(k\) 必然有 \(a_k \in [a_i, a_j)\),另外,有 \(\left| a_i - a_k \right| < \left| a_j - a_k \right|\),则有 \(a_k < \dfrac{a_i+a_j}{2}\),每次除以 \(2\),最终只有 \(O(\log V)\) 个有效的右端点。\(a_j < a_i\) 也是同理,这样有用对只有 \(O(n \log V)\) 级别。为了快速找出这些有用对,可以按照权值顺序建主席树,在上面二分。这样可以在 \(O(n \log n \log V)\) 的复杂度内找出所有有用对。然后对着右端点扫描线,用一棵维护区间取 \(\min\) 的线段树即可。总复杂度 \(O(n \log n \log V + m \log n)\)。
Problem H. CF1455G Forbidden Value
题意:
已知初始值 \(x=0\),给定 \(s\)。有 \(n\) 次命令,每次给定下面 \(2\) 种命令:
set
\(y\) \(v\),令 \(x \leftarrow y\),或花费 \(v\) 元钱删除该命令;if y …… end
,如果 \(x=y\),执行if...end
中的命令,否则跳过该if...end
。
你需要使用最少的花费,使得无论运行到哪里,都有 \(x \neq s\)。
\(1 \leq n,y \leq 2 \times 10^5\),\(1 \leq v \leq 10^9\)。
解法:
考虑整个操作显然是一个树形结构。考虑树上 DP,记 \(f_{i,j}\) 表示从 \(i\) 子树开始,初始值为 \(i\) 上的这个点,最终值为 \(j\) 时的最小修改次数。显然这是一个可以整体 DP 的过程,子树合并只需要直接线段树合并,并同时维护区间加区间最小值即可。总复杂度 \(O(n \log n)\)。
Problem I. CF1320E Treeland and Viruses
题意:
有一棵有 \(n\) 个节点的树,\(q\) 次询问(询问互相独立),每次给定 \(k_i\) 个颜色,每个颜色有一个起始点 \(v_j\) 和移动速度 \(s_j\),每一个颜色在每一次操作中会使它周围没有被染色的连通块上与它的距离不超过 \(s_j\) 的点全部染为这一个颜色,每一轮中,颜色从 \(1\) 到 \(k_i\) 依次开始操作,一直到所有点全部被染色为止,再询问 \(m_i\) 个关键点的颜色。
\(1 \leq n,q \leq 2 \times 10^5\),\(\sum k_i,\sum m_i \leq 2 \times 10^5\),\(s_j \leq 10^6\)。
解法:
考虑每次询问时将颜色点和询问点同时建立虚树,然后跑最短路,在 Dijkstra 之前将所有颜色点扔进队列,同时使用时间和编号的二元组进行排序即可。使用 ST 表求 LCA 可以做到 \(O(n\log n)\),如果每次都 \(O(\log n)\) 求 LCA 可以做到 \(O(n\log^2 n)\)。
Problem J. P10795 『SpOI - R1』Lamborghini (Demo)
题意:
给你一棵无根树,每个点 \(i\) 有两个属性 \(t_i,v_i\)。
定义有向路径 \(i\to j\) 的 \(f_{i,j}\) 为:
- 若 \(i\to j\) 上 \(t_x\) 最小的点为 \(x\) 且 \(v_j\leq v_x\leq v_i\),则 \(f_{i,j}=x\)。
- 否则,\(f_{i,j}=0\)。
求 \(\sum\limits_{i=1}^n\sum\limits_{j=1}^n f_{i,j}\)。
\(t\) 互不相同,\(1\leq n\leq 10^5\),\(1\leq t_i,v_i\leq 10^9\)。
解法:
此题给予了我们一个另类的刻画树上路径最值的技巧。
如果直接点分治,可能可以通过处理很多东西做出,但是不够厉害。
考虑路径点权最值。对于每条边 \((u,v)\),令其边权为 \(\min\{t_u,t_v\}\),则显然有路径点权最小值等于路径边权最小值。然后考虑对树建立 Kruskal 重构树!这样任意两点 \((u,v)\) 的路径最小值为重构树上 LCA 的点权。枚举 LCA,则只需要维护子树小于等于某数个数。拆成 DFN 序做数点,或者启发式合并,或者线段树合并均可。复杂度 \(O(n \log n)\)。
Problem K. CF1575E Eye-Pleasing City Park Tour
题意:
有一个城市公园形如一棵树,它的顶点是 \(n\) 个景点,由 \(n-1\) 条道路连接,第 \(i\) 个景点有一个观赏值 \(a_i\)。每条道路都有一种颜色 \(t_i\),如果 \(t_i=0\) 则为黑色,\(t_i=1\) 则为白色。同时公园里还配有黑白两种颜色的车。
Caropul 想乘车游览这个公园,但什么颜色的车走什么颜色的道路,想走另一种颜色的道路需要换一次车。
定义一次游览 \((u,v)\) 为走一条从 \(u\) 景点开始,到 \(v\) 景点结束的简单路径(即路径上的每个景点只能经过一次),\(f(u,v)\) 为这条路径经过的所有景点(包括 \(u,v\))的观赏值之和。
现在 Caropul 想知道对于所有不超过 \(k\) 次换车的游览 \((u,v)\) ,\(f(u,v)\) 的和对 \(10^9+7\) 取模的结果,其中 \(1\le u\le v\le n\)。
注意最开始上车不算一次换车。
解法:
简单点分治。
注意到对于点分治重心,只需要分别考虑唯一的出边是黑或白即可。使用树状数组可以简单做到两个 \(\log\)。
Problem L. CF2030F Orangutan Approved Subarrays
题意:
有一个正整数集合 \(S\),初始为空。称一个长度为 \(n\) 的正整数序列 \(a_1,a_2,\cdots,a_n\) 是好的,当且仅当可以通过若干次如下操作将序列删空:
每次选择序列的一段区间 \([l,r]\) 使得区间中所有数相同,且 \(a_l \notin S\)。删去 \(a_{l},a_{l+1},\cdots,a_r\),并在 \(S\) 中加入 \(a_l\)。
给定一个长度为 \(n\) 的序列,\(q\) 次询问,每次给定区间 \([l,r]\),判断 \(a_l,a_{l+1},\cdots,a_r\) 是否是好的。
\(n, q \leq 2 \times 10^5\),\(1 \leq a_i \leq n\)。
解法:
考虑固定 \(l\),则使得 \([l,r]\) 是好的的 \(r\) 必然是一段以 \(l\) 开始的区间。我们希望对于每个 \(l\) 求 \(nxt_l\) 表示最大的合法 \(r\)。则询问相当于判断 \(nxt_l \geq r\)。
考虑双指针。容易发现在加入右侧一个数的时候,如果存在某种数,与这个数出现的位置有交但不包含则判定为不合法。考虑目前区间 \([l,r]\),对每个 \(i \in [l,r]\) 维护 \(pre_i\) 表示最大的 \(j\) 满足 \(a_j = a_i\) 且 \(j \in [l,r]\)。不存在则 \(pre_i = +\infty\)。容易发现往后加和在前面删都是单点修改区间求 \(\min\),使用线段树维护,复杂度 \(O(n \log n + q)\)。
Problem M. Public NOIP Round7 T4 冒泡排序
题意:
给定一个长度为 \(n\) 的非负整数序列 \(b_1,b_2,\cdots,b_n\)。
对于一个长度为 \(k\) 的非负整数序列 \(a_1,a_2,\cdots,a_k\),一次冒泡排序形如下述代码:
for i = 1 to k-1:
if a[i] > a[i + 1]:
swap(a[i], a[i + 1])
给定 \(q\) 次询问,每次给定 \(l,r,k,x,y\),将 \(b_{l},b_{l+1},\cdots,b_r\) 复制到 \(a_1,a_2,\cdots,a_{r-l+1}\),对 \(a\) 进行 \(k\) 次冒泡排序后查询 \(\sum \limits_{i=x}^y a_i\)。
\(1 \leq n \leq 10^6\),\(1 \leq q \leq 5 \times 10^5\),\(0 \leq b_i \leq 10^9\),时限 \(4\) 秒。
解法:
好题。
先考虑一个看着可以优化的暴力。
首先我们将 \([x,y]\) 变成后缀差分形式,即 \([x,r-l+1]-[y+1,r-l+1]\)。
我们枚举值域中的数 \(x\),将区间中大于 \(x\) 的数标记为 \(1\),小于等于 \(x\) 的数标记为 \(0\)。发现询问后缀中所有 \(1\) 最终都会在后缀中,同时非后缀中有若干 \(1\) 会移动到后缀内。仔细思考发现每次冒泡排序,对于所有 \(0\),只要前面有 \(1\) 就会往前一步,所有 \(1\) 都会移动到末尾或者下一个 \(1\) 前面。那么有多少 \(1\) 会从前缀移动到询问后缀呢?事实上,记区间长度 \(m=r-l+1\),目前询问后缀为 \([i,m]\),\(c_0[l,r]\) 表示区间 \([l,r]\) 中标记为 \(0\) 的数的个数,\(c_1[l,r]\) 同理。则我们声称有 \(\min\{c_1[1,l-1],c_0[l,l+k-1]\}\) 个 \(1\) 会从前缀移动到询问后缀。这虽然不容易注意到,但并不难理解。至多有前缀 \(1\) 个数能移动到后缀,同时只有 \([l,l+k-1]\) 这一段内的 \(0\) 能为前面的 \(1\) 提供空位。注意到对于序列离散化后枚举值域可以变成枚举 \(a_i\),于是得到了一个 \(O(qn^2)\) 的做法。
但是得到了这个做法之后就没啥难度了。注意到这个 \(\min\) 随着枚举的 \(x\) 增大,一边的值不降,一边的值不升。这个分界点很容易在主席树上二分求出。求完后查询是一个主席树区间询问,直接做就行,复杂度 \(O(q \log n)\)。
Problem N. P11220 【MX-S4-T4】「yyOI R2」youyou 的三进制数
题意:
现在有 \(0 \sim n\) 共 \(n + 1\) 个数。
定义 \((x)_{3}\) 表示十进制数 \(x\) 的三进制形式。如果没有特别强调,那么这些数均为十进制形式。
youyou 想构造一个序列长度为 \(p\)(\(p \ge 1\))的非负整数序列 \(a\)。使之满足:
- \(a_i \in [0,n]\)。
- 不存在 \(i,j\)(\(1 \le i <j \le p\)),使得 \(a_i = a_j\)。
- 对于任意 \(1 \le i < n\),\(a_i\) 与 \(a_{i+1}\) 至少满足以下四个条件中的一个:
- \((a_i)_3\) 去掉最后一位,恰好等于 \((a_{i+1})_3\)(若只有一位,则去掉后的数字为 \(0\))。
- 在 \((a_i)_3\) 末尾添上某一位 \(t(0 \le t \le 2)\),恰好等于 \((a_{i+1})_3\)(若 \(a_i = 0\),则添加后舍去前置 \(0\))。
- \(a_i \le w\), \((a_i)_3\) 的末尾不是 \(0\),且将末尾的一位数字移到开头与 \((a_{i + 1})_3\) 相等。
- 当 \((a_i)_3\) 长度 \(\ge 2\),且 \((a_i)_3\) 次高位非零时,将 \((a_i)_3\) 开头的一位数字移到末尾,形成的数的十进制值 \(\le w\),且恰好等于 \((a_{i+1})_3\)。
这样的序列 \(a\) 被称为“完美的”。
youyou 认为,如果十进制三元组 \((x,y,z)\) 是好的,必须满足以下条件:
- \(0 \le x,y,z \le n\),\(x \neq y\)。
- 存在至少一个”完美的“序列 \(b\),使得十进制下有 \(b_1=x\),\(b_s = y\)。其中 \(s\) 为序列长度。
- 存在至少一个”完美的”序列 \(c\),使得十进制下有 \(c_1=z\)。同时,对于上述任意的 \(b\),均有恰好一对 \((i, j)\),满足 \(1 \le i \le |b|\),\(1 \le j \le |c|\),使得 \(b_i = c_j\)。
对于每一个 \(0 \le z \le n\),求能构成“好的”三元组 \((x,y,z)\) 的有序对 \((x,y)\) 的个数。
\(1\le n \le 3 \times 10^5\),\(0 \le w \le n\)。
解法:
这么连边真有啥意义吗。
对于所有可以相邻的数连边,事实上可以发现所有边都是双向的。连出后可以发现图一定连通。
完美的序列事实上就是一条简单路径,好的三元组 \((x,y,z)\) 其实就是存在一条从 \(z\) 出发的简单路径,使得 \(x\) 到 \(y\) 的所有简单路径都和这条路径有恰好一个交点。
那么对于固定的 \(z\),哪些 \((x,y,z)\) 是好的呢?我们声称若 \(x\) 到 \(y\) 的路径有必经点,且存在一条 \(z\) 出发的路径经过此必经点,且这条路径不与任意一条 \(x\) 到 \(y\) 路径在必经点外重合。证明是比较显然的,如果 \(x\) 到 \(y\) 的所有简单路径与 \(z\) 开始的简单路径相交于至少两个点,则必然存在某条简单路径也经过至少两个点。
对图建立圆方树,则判定条件变为 \(x\) 到 \(y\) 路径上离 \(z\) 最近的点为圆点。枚举这个最近点,然后枚举 \(z\) 所在子树,做子树加,最后进行查询,直接差分维护 DFN 序即可。复杂度线性。建图若实现不精细则是 \(O(n \log n)\) 的。
Problem O. 云斗学院 2024 S 赛前模拟 T3 魔法序列
题意:
给定一个长为 \(n\) 的整数序列 \(a_1,a_2,\cdots,a_n\),然后给 \(q\) 次询问,每次给定 \(l,r,x\),求 \(\max \limits_{i=l}^r (a_i \operatorname{OR} x)\)。其中 \(\operatorname{OR}\) 表示二进制下或运算。
特别地,保证 \(a_1 < a_2 < \cdots < a_n\)。
\(1 \leq n, a_i, q, x < 2^{20}\),时限 \(3\) 秒。
解法 \(1\):
对着题解念一遍。
我们考虑先将询问离线。
我们建立两棵 0-1 Trie,第一棵插入值域内所有数,且从低到高位插入。第二棵将所有 \(a_i\) 插入。然后我们考虑在第一棵上 DFS,在每个叶子节点求所有 \(x=val_{leaf}\) 的答案。在 DFS 过程中,我们在第二颗树上动态维护每个数和目前的值的按位或。可以发现在第一棵树上往 \(1\) 的边走,其实是在第二棵树上将所有这一位为 \(0\) 的子树加 \(2^k\)。又由于序列单增,所以询问直接类似线段树查询区间 \(\max\) 即可。由于两棵树建立方向相反,所以复杂度为 \(O(\sum \limits_{i=0}^{20} 2^i2^{20-i+1})=O(V \log V)\),可以通过。
解法 \(2\):
这个做法是 \(O(V \log^2 V)\) 的,但依赖递增性质是不是有点菜了!
我们考虑从高到低贪心,每次询问变为给定 \(k\),判定区间内是否存在一个数二进制下是 \(k\) 的超集,即包含 \(k\)。
但是这个问题好像有点难啊。但是你别急,考虑什么东西能刻画这种东西。虽然所有数不同,但枚举子集复杂度也太差了,空间显然也不对。但是你考虑你可以 FWT!你希望对于每个值域内的数,维护一棵线段树,线段树上每个位置 \(i\) 的权值为 \(0/1\) 表示 \(a_i\) 是否为这个数的超集。FWT 的时候你只需要维护线段树合并。因为你做的是贪心,所以必须在线处理询问,线段树合并时要可持久化一下。这样空间太烂了,只能过 \(n < 2^{18}\) 的 \(75\) 分,但确实不依赖于递增的性质。这也是我赛时写的做法。
Problem P. P3747 [六省联考 2017] 相逢是问候
题意:
你要维护一个长度为 \(n\) 的非负整数序列 \(a_1,a_2,\cdots,a_n\),同时给定两个正整数 \(c,p\)。
一共有 \(m\) 个操作,可以分为两种:
-
0 l r
表示将第 \(l\) 个到第 \(r\) 个数( \(a_l,a_{l+1} ...a_r\))中的每一个数 \(a_i\) 替换为 \(c^{a_i}\),即 \(c\) 的 \(a_i\) 次方,其中 \(c\) 是输入的一个常数,也就是执行赋值 \(a_i = c^{a_i}\)。 -
1 l r
求第 \(l\) 个到第 \(r\) 个数的和,也就是输出 \(\sum_{i=l}^{r}a_i\)。
因为这个结果可能会很大,所以你只需要输出结果对 \(p\) 取模的结果即可。
\(1\le n,m \le 5\times 10^4\),\(1 \le p \le 10^8\),\(0< c < p\),\(0 \le a_i < p\),时限 \(2\) 秒。
解法:
考虑一个经典套路。
对于幂塔而言,根据拓展欧拉公式可以递归求解,但事实上可以发现每一步操作模数 \(p\) 都会递归变为 \(\varphi(p)\),根据经典结论我们知道,不断执行 \(p \leftarrow \varphi(p)\),最终 \(p\) 会在 \(O(\log{p})\) 轮内变为 \(1\)。证明考虑若 \(p\) 为偶数,则 \(\varphi(p) \leq \dfrac{p}{2}\),若 \(p\) 为奇数,则除 \(p=1\) 外,\(\varphi(p)\) 为偶数。
这样我们可以发现,对于每个位置,如果幂塔层数超过 \(p\) 变到 \(1\) 所需次数,那么对其继续增加层数并不会影响其值,因为递归到最后,其值甚至都不受 \(a_i\) 的影响。这样我们维护一棵线段树,每个点维护区间内操作次数最小值和区间和。修改暴力递归到所有有意义的叶子节点,然后直接递归求解不超过 \(O(\log {p})\) 层的幂塔。这样总复杂度为 \(O(n \log^3 p)\),其实并不能确保通过。事实上有两种解决方案。一种是注意到数据很弱,将幂塔层数上限调低就可以通过本题,另一种是注意到能优化的复杂度的在快速幂上,我们只需要快速计算 \(c^x\) 对若干常数取模的结果。模数数量为 \(O(\log p)\) 量级,对于每个模数光速幂即可。复杂度为 \(O(n \log^2 {p}+\sqrt{p}\log{p})\)。
Problem Q. CF2009G3 Yunli's Subarray Queries (extreme version)
题意:
给定 \(n,k\) 和一个长度为 \(n\) 的每个数不超过 \(n\) 的正整数序列 \(a_1,a_2,\cdots,a_n\),对于序列 \(b_1,b_2,\cdots,b_m\),其中 \(m\geq k\),定义 \(f(b)\) 为最小的操作次数,使得存在一个子区间是公差为 \(1\) 的等差数列,操作是每次选任意一个 \(b_i\) 并将其修改为任意一个整数。
\(q\) 次询问,每次给定 \(l,r\),满足 \(r \geq l + k - 1\),你需要求出 \(\sum \limits_{i=l}^{r-k+1} \sum \limits_{j=i+k-1}^r f([a_i,a_{i+1},\cdots,a_j])\)。
\(1 \leq k \leq n \leq 2 \times 10^5\),\(1 \leq q \leq 2 \times 10^5\),\(1 \leq a_i \leq n\)。
解法:
简单题。
容易发现 \(f(b)\) 等于序列长度减 \(c_i=b_i-i\) 的 \(c\) 的众数出现次数。
离线,对右端点扫描线,你需要维护前缀取 \(\min\),区间历史和,直接吉司机线段树上去即可。
代码贺的题解。
Problem R. P11160 【MX-X6-T6】機械生命体
题意:
维护一个可重集 \(S\),初始为空。支持 \(q\) 次如下操作:
1 x
,你需要在 \(S\) 中加入一个数 \(x\)。2 x
,你需要在 \(S\) 中删除一个数 \(x\)。保证此时 \(S\) 中存在至少一个 \(x\)。如果存在多个 \(x\),则仅删除一个。3 x k v
,你需要对 \(S\) 中所有满足 \(\operatorname{lowbit}(x\oplus y)\geq 2^k\) 的 \(y\) 增加 \(v\) 并对 \(2^{32}\) 取模。4 x
,你需要求出 \(\max\limits_{y\in S} \operatorname{lowbit}(x\oplus y)\)。保证此时 \(S\) 不为空。
其中 \(\operatorname{lowbit}(x)\) 表示最大的整数 \(k\),使得 \(k\) 是 \(2\) 的整数次幂并且整除 \(x\)。\(\oplus\) 代表按位异或。
特殊的,我们在本题定义 \(\boldsymbol{\textbf{lowbit}(0)=2^{32}}\)。
\(1 \leq q \leq 5 \times 10^5\),值域 \(2^{32}-1\),时限 \(2\) 秒,空间限制 \(512\) MB。
解法:
没有操作三是简单的,从低到高位建立 01-Trie,查询直接从低到高匹配就行了。
但是操作三很奇怪,01-Trie 上的加法首先让我们想到的是那个全局加 \(1\) 的做法,但是这里加的是 \(v\)。显然操作三是一个子树加,但是我们先考虑全局加怎么做。
对于每个点,维护加法标记,下传时,如果标记为奇数,做一次子树加一然后标记减一。将标记除以二后传给两个儿子。进一步地,子树加一可以直接交换左右儿子然后给左子树标记加一。
子树加并不能直接按照全局加将标记放上去,因为事实上这里的加法标记对应的是真正要加的除以 \(2^{dep}\) 所得结果,但是子树到根的链上的信息并无法维护。
然而仿照线段树分裂合并,直接将整棵子树分裂出来做全局加,然后合并回去即可。复杂度 \(O(q \log V)\)。
Problem S. P11038 【MX-X3-T5】「RiOI-4」Countless J-Light Decomposition
题意:
给定一棵有根带权树,结点以 \(1\sim n\) 编号。根结点编号为 \(1\),边权均为正整数。
定义这棵树的剖分为对于每个结点,选择一些儿子(可以都选或都不选)为重儿子的方案。重儿子和其父亲的边称为重边。不是重边的边称为轻边。
定义一个剖分是 \(i\) 重的,当且仅当对于每个结点,其重儿子数量不超过 \(i\)。
定义一个剖分是 \(j\) 轻的,当且仅当对于每条从根(编号为 \(1\) 的结点)出发的简单路径,其经过的轻边的边权和不超过 \(j\)。
对于 \(i=0,1,\cdots,n-1\),请求出最小的 \(j\),使得存在一个 \(i\) 重的剖分是 \(j\) 轻的。
\(n \leq 2 \times 10^5\),\(1 \leq w \leq 10^9\),\(1\) 秒。
解法:
先考虑暴力,对于每个 \(i\) 进行 DP,记 \(f_u\) 表示在 \(u\) 子树内的答案,转移直接从儿子里取 \(i\) 大的转移即可。复杂度 \(O(n^2 \log n)\) 或 \(O(n^2)\)。
进一步地,如果某个点儿子数量不超过 \(i\),其 \(f\) 值就是儿子的 \(f\) 最大值。考虑对于每个 \(i\),建立儿子个数大于 \(i\) 的点的虚树,虚树总点数是 \(O(\sum deg_i)=O(n)\) 量级的。转移时直接枚举儿子复杂度不对,但是使用平衡树维护每个点的所有儿子贡献即可。