2025.5做题记录

你说得对,但是感觉不如线段树。线段树,是一种高级数据结构。设n是数据规模,每个结点代表一个区间,通过二分递归分割空间,若区间修改与查询的复杂度可降至O(logn),则称其为区间问题的完全体。假设一棵线段树处理规模1e6的数组,那么它能在30层内覆盖所有区间,且有单点修改、区间查询、懒标记优化三大特性,归根到底就是任意区间操作都能被分解成O(logn)个结点处理。你的算法基础很差,我现在每天用线段树都能处理1e5次操作请求,每月维护3e6次动态区间最值,相当于现实世界中3e18次暴力扫描,换算成O(n)算法要跑950年。虽然我只有12岁,但超越了中国绝大多数人(包括你)的水平,这便是线段树给我的骄傲的资本。

洛谷P3604 美好的每一天
由于只有 \(26\) 个小写字母,考虑状压成 \(26\) 位二进制数,然后一个区间是回文串就等价于区间异或和的 \(\operatorname{popcount}\) 小于等于 \(1\)
由于是区间异或和,可以做个前缀和,然后把查询的左端点减一。
用莫队,开一个 \(cnt\) 维护 \(0\)\(2^{26}-1\) 的出现次数,每次加/删数的时候就把和这个数异或起来的 \(\operatorname{popcount}\) 小于等于 \(1\) 的数的 \(cnt\) 加进去。
洛谷P4074 [WC2013] 糖果公园
树上待修莫队板子题。
其实很简单,把树上莫队和待修莫队的代码拼在一起就得了。
洛谷P4175 [CTSC2008] 网络管理
显然是树上带修莫队。
维护 \(k\) 大可以用权值线段树,但是复杂度是根号老哥,不知道能不能过(?。
或者用值域分块。维护每个块的数的出现次数和每个数的出现次数,查询时先找答案在哪个块,再找答案。当然要离散化。
洛谷P7377 [COCI 2018/2019 #5] Parametriziran
考虑 \(s\)\(t\) 匹配的条件是什么: 如果 \(s_i=?\),那么 \(t_i\)是什么都行;否则,\(t_i=s_i\)\(t_i=?\)
考虑对每一位维护这个位置上等于某个字符的字符串编号集合,可以用 bitset 维护是否满足条件。
查询的时候,开一个全 \(1\)bitset。枚举当前字符串的每一位。如果这个位置的字符不是问号,就与上当前位是这个字符和当前位是问号的或。然后给答案加上这个 bitset\(1\) 的个数,如果当前字符串全是问号就是 \(i-1\)
更新的时候直接设为 \(1\) 就得。
spoj288
不难发现是密勒瑞滨板子。
洛谷P6810 「MCOI-02」Convex Hull 凸包
神秘推式子题,默认 \(n<m\)

\[\begin{aligned}& \sum\limits_{i=1}^{n}\sum\limits_{i=1}^{m}\tau(i)\tau(j)\tau(\gcd(i,j))\\=& \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\tau(i)\tau(j)\sum\limits_{k\mid i,k\mid j}1\\=& \sum\limits_{k=1}^{n}\sum\limits_{1\le i\le n,k\mid i}\tau(i)\sum\limits_{1\le j\le m,k\mid j}\tau(j) \end{aligned}\]

考虑先预处理出 \(\tau\),就可以枚举 \(k\) 直接算 \(\sum\limits_{1\le i\le n,k\mid i}\tau(i)\)\(\sum\limits_{1\le j\le m,k\mid j}\tau(j)\),再乘起来。
复杂度是一个 \(\log\)
洛谷P3488 [POI 2009] LYZ-Ice Skates
\(a_i\) 表示有几个 \(i\) 号脚的人。
如果 \([l,r]\) 号脚的人都能穿鞋,那么满足 \(\sum\limits_{i=l}^{r}a_i \le (r-l+1+d)\times k\),即 \(\sum\limits_{i=l}^{r}(a_i-k) \le d\times k\)。全局满足条件就是 \(\forall 1\le l\le r\le n-d,\sum\limits_{i=l}^{r}(a_i-k) \le k\times d\),即全局最大子段和小于等于 \(k\times d\)
用线段树维护。
洛谷P2943 [USACO09MAR] Cleaning Up G / P11311 漫长的小纸带
\(dp_i\) 表示前 \(i\) 个的最小耗时。
不难得出 \(dp_i=\min_{j=1}^{i}\{cnt_{[j,i]}^2 + dp_{j-1}\}\),其中 \(cnt_{[j,i]}\) 表示 \([j,i]\) 的不同数字个数。
不难发现 \(cnt\) 加一时是在每个数字最后出现的位置,考虑用 set 维护这个东西,然后从大到小枚举,更新 \(dp_i\)
但是还是过不了。
可以发现 \(dp_i\) 最大为 \(i\),所以当 \(cnt^2 > i\) 时可以直接退,复杂度是根号。
洛谷P1937 [USACO10MAR] Barn Allocation G
把区间按右端点从小到大,左端点从大到小排序,用线段树维护区间加区间最小值,每次看能不能加进去,然后区间减一。
不会证,但这是对的。
uva1437 String painter
\(dp_{i,j}\) 表示把空串的区间 \([i,j]\) 内的字符改成对的的最小操作次数,显然可以用区间 dp 做。
\(dp1_i\) 表示把 \(A\) 的前 \(i\) 个字符改成对的的最小次数。
\(A_i=B_i\) 时,\(dp1_i=dp1_{i-1}\)
然后把前面的转移一下,\(dp1_i=\min\limits_{j=0}^{i-1}\{dp1_j+dp_{j+1,i}\}\)
洛谷P12003 在小小的奶龙山里面挖呀挖呀挖(加强版)
奶龙题。
考虑对值域根号分治,容易发现每个 \(a_i\) 最多只有一个质因子大于等于 \(10^4\)
然后把 \(a_i\) 分解质因子,把大于根号的质因子单独处理,也就是路径上不同的数的个数,可以用树上莫队。
考虑小于等于根号的质因子。因为 \(10^4\) 以内的质数只有大约 \(1300\) 个,所以可以用 bitset 维护每个点的质因子,查询就是路径或。
但是这样做的复杂度是双老哥乘上 \(\frac{1300}{w}\),过不了。可以预处理每个点到重链顶端的 bitset 或,就能去掉一个老哥。
洛谷P5397 [Ynoi2018] 天降之物
先对每个块做个块内离散化。
可以维护块内每个数第一次/最后一次出现的位置,块内每两个数的答案,块内每个数的离散化值。
先考虑修改:
如果没有 \(x\),直接不管这个块。
如果有 \(x\) 没有 \(y\),直接把 \(y\) 的离散化值改成 \(x\) 的。
如果都有,就直接重构这个块。
由于每个块的重构次数是根号级别,其他的都是 \(O(1)\),所以修改的总复杂度是 \(O(n\sqrt{n})\)
查询就很简单了,直接模拟就行。
下面是卡常经历:
答案是对的。第三次交 26pts
调块长。第五次交 40pts
把离散化值的数组的维度交换一下。第七次交 92pts
查询时,如果 \(x=y\) 就看这个数有没有出现,否则,如果当前答案为 \(1\) 就直接返回。第八次交 94pts
继续调块长。第十一次交 100pts
洛谷P8422 [THUPC 2022 决赛] 德州消消乐
感觉这题真开始写的时候其实没那么石山(?
做法是模拟,牌型奖分直接搜。
一些细节:
如果交换的两个点不相邻/被删了/不在 \([1,n]\)\([1,m]\) 内就直接不合法。
主颜色只有交换之后那个颜色被删了才算。
组合奖分是同颜色的四连通块。
洛谷P3071 [USACO13JAN] Seating G
双倍经验P2894。
把没人设为 \(1\),有人设为 \(0\),然后建线段树,就变成了区间修 \(0\)/\(1\),区间查询。
考虑维护区间最大子段和,区间左/右极长连续 \(1\) 长度,区间修打个 tag 是简单的,区间查询直接讨论左子节点,左子节点的右边加右子节点的左边,右子节点。
洛谷P5631 最小mex生成树
线段树分治。
把边按 \(w\) 排序,用并查集维护连通性,每次把大于 \(mid\) 的边加进去,递归左边,然后删了,把小于等于 \(mid\) 的边加进去,递归右边。
到最下面的时候如果图联通就直接输出。判断联通可以看并查集上 \(1\) 的根节点的 \(siz\) 是不是等于 \(n\)
洛谷P4585 [FJOI2015] 火星商店问题
直接线段树套 01trie,每个节点开一棵 trie 就做完了。
洛谷P6815 [PA 2009] Cakes
对每条边定向,从度大的连向度小的,如果一样就是编号小的连向编号大的。
然后枚举每个点,把点连向的点标记,直接枚举点连向的点连向的点,如果有标记就是三元环。
这样做是 \(m \sqrt{m}\) 的,很神奇。
洛谷P5355 [Ynoi Easy Round 2017] 由乃的玉米田
只看前三个操作就是 P3674,所以只看第四个操作。
根号分治,如果 \(x \ge \sqrt{V}\) 就直接暴力,\(V\) 是值域,否则把询问挂到区间右端点上。
记录每个数最后出现的位置和每对商为 \(x\) 的左边那个最右是哪,枚举每个点,枚举 \(x\) 更新那两个数组,然后把询问搞一下就行。
洛谷P4219 [BJOI2014] 大融合
离线建森林,然后搜 \(dfn\) 序。
初始的时候往每个点的线段树插个 \(dfn_i\),加边就是线段树合并。
查询的时候,设 \(u\) 是深的那个点,\(f\) 是并查集的根节点,要查的是 \(f\) 的线段树里有几个是森林上 \(u\) 子树里的节点,设为 \(x\),答案就是 \(x \times (siz_f - x)\)\(siz_f\) 是当前线段树一共有几个点。
在经过 \(dfn\) 转化后就是线段树合并区间查询。
CF609F Frogs and mosquitoes
容易发现青蛙的坐标是不变的。按坐标从小到大排序,建一棵线段树维护每个青蛙能吃到的最右的位置。
修改的时候,二分最后一个 \(x_i \le p\) 的点,然后线段树二分 \([1,i]\) 里最左的能吃到这个蚊子的位置,如果没有就丢进一个 multiset 里。
如果能吃掉,设这个青蛙位置是 \(j\),先把它的舌头长度加一下,然后看 multiset 里有没有它能吃到的,有就更新。
统计答案可以对线段树的子节点记录这个位置的原位置,修改的时候更新一下。
CF600F Edge coloring of bipartite graph
猜测最小染色是所有节点的度的最大值。
考虑构造,对每个节点记录下从某个颜色的边能到的点是哪个,没有就是 \(0\)
枚举边,设这个边为 \((u,v)\),找出 \(u\)\(v\) 两个点的编号最小的没用过的颜色。如果相等就直接标号,否则从一个点出发,把它的颜色暴力更改。
CF56E Domino Principle
简单题。
先按 \(x\) 从小到大排序。
\(dp_i\) 表示 \(i\) 倒下去后最远倒下的位置。
从后往前枚举,初始设 \(dp_i=i\),然后一直往后跳。如果 \(i\) 能压到 \(dp_i+1\),就把 \(dp_i\) 改成 \(dp_{dp_i+1}\),直到 \(dp_i=n\)\(i\) 压不倒 \(dp_i+1\)
复杂度显然是对的。
CF1045G AI robots
发现两个机器人能互相看到当且仅当视野小的能看到视野大的。
把机器人按 \(r\) 排序,然后cdq分治。
两边做完后双指针,枚举左边的机器人,把右边的机器人里智商满足条件的加进去,就变成了单点修区间查,可以离散化后用树状数组维护。
洛谷P5064 [Ynoi Easy Round 2014] 等这场战争结束之后
神秘无敌超级卡时间卡空间题。
看到操作二,考虑建操作树,也就是这个操作的上一个状态向这个操作连边,没有就是 \(0\)
然后从 \(0\) 开始跑树,连边删边用并查集维护,离散化后维护 \(k\) 小用值域分块,维护以每个点为根的权值有多少个是某块,连边删边是根号的。
查询的时候,无解就是 \(k\) 大于点的个数,枚举答案在哪个块,然后枚举块内的每个数,如果这个权值对应的点的并查集祖先是当前这个就是有贡献的。
因为要找每个权值对应的点,所以相同的权值离散化后要不同,还是很好做的。
交上去发现可能会 TLE/MLE,考虑优化:
块长开到 \(4500\) 左右。
维护 \(k\) 小用的那个数组用 short
存边用链式前向星。
并查集找祖先的那个函数开 inline
gym105486I
不难,但是好玩。
设满足 \(a_i>a_{i+1},i\in[1,n-1]\)\(i\) 称为断点,可以发现每个断点到上一个断点加一都是一个不下降子串。
容易发现满足条件的 \(k\) 一定是所有断点编号的因子,也就是 \(\gcd\) 的因子,所以考虑维护断点编号,修改是简单的。
可以用线段树维护,设 \(\gcd(i,0)=i\)\(\gcd(0,0)=0\),如果这个点是断点,那么这个点的权值就是这个点的编号,否则是 \(0\),就变成了单点修全局最大值。
洛谷P12598 参数要吉祥
莫队,然后移动的时候用值域分块维护 \(x \times c(x)\)
CF1646F Playing Around the Table
考虑先让每个人都有所有种类的牌,方法是每次把自己重复的丢出去,如果没有就把上一个人丢过来的丢到下一个人。
做完之后的构造是简单的。
洛谷P5471 [NOI2019] 弹跳
好题。
容易发现是正边权的最短路,用 dijkstra。
考虑把每个矩阵看成一个虚点,对虚点跑 dij,每次松弛的时候可以往矩阵内的点往外连的矩阵更新。
考虑用线段树维护横坐标在某个区间上的点,每次松弛的时候,在线段树上找到这个矩阵内的点,用点更新完后就删了,因为只会最多只会被更新一次。
洛谷P3514 [POI 2011] LIZ-Lollipop
很妙的题。
可以发现如果 \(k+2\) 有解,那么 \(k\) 也有解,可以从两边删掉一个 2 或者删掉两个 1
考虑计算出能取到的最大的奇数和偶数,然后往下扩展,显然有一个的最大值是全加起来。
考虑如何构造另一个,可以发现一定是从前面或后面选一边删几个,因为如果有一边选的总和是偶数,那还不如不选。
然后预处理出答案后就是输出。
洛谷P5692 [MtOI2019] 手牵手走向明天
可以发现这题是第四分块P5397的区间版本,考虑使用第四分块的序列分块版本然后改下代码。
查询比较简单,散块的询问是简单的,整块就是第四分块那样。
修改整块和第四分块差不多,但是要对每个块开个桶记录有什么离散化值是全没了可以给另一个数的。
修改散块的时候,如果改成的数没有就从桶里拿一个离散化值,如果没有就新开一个,然后重构这个块。
重构的时候,可以发现块内的答案之和修改的两个数有关,先从前往后扫一遍,再从后往前扫一遍,扫的时候处理。
修改的时候要把原数组(当然是离散化后的)也改一下,因为重构的时候要用。
洛谷P5501 [LnOI2019] 来者不拒,去者不追
因为我是边写边想的所以可能会长一点。
考虑莫队,设 \(f(x,y)=\sum\limits_{i=1}^{y}[a_i<a_x]\)\(g(x,y)=\sum\limits_{i=1}^{y}[a_i>a_x]\times a_i\)
设当前左端点是 \(l\),先考虑右端点从 \(x\) 向右移到 \(y\),对答案的贡献就是 \(\sum\limits_{i=x+1}^{y}(f(i,i-1)-f(i,l-1)+1)\times a_i+g(i,i-1)-g(i,l-1)\),拆一下就是 \(\sum\limits_{i=x+1}^{y}(f(i,i-1)+1)\times a_i+\sum\limits_{i=x+1}^{y}g(i,i-1)-\sum\limits_{i=x+1}^{y}f(i,l-1)\times a_i-\sum\limits_{i=x+1}^{y}g(i,l-1)\)。其它三种移动端点是类似的。
可以发现前面两坨可以预处理出,在莫队的时候直接算,后面两坨就是二次离线,带个值域分块做。
洛谷P3364 Cool loves touli
考虑 dp,转移是 \(f_i=\max\limits_{l_j<l_i,a_j \le s_i,w_j \le a_i}\left\{dp_j\right\}+1\),然后 cdq 分治就得。
洛谷P3658 [USACO17FEB] Why Did the Cow Cross the Road III P
水题。
设品种 \(i\) 在左边出现的位置是 \(a_i\),在右边出现的位置是 \(b_i\)
要统计的就是满足 \(a_i<a_j,b_i>b_j,|i-j| > k\) 的对数。
然后按 \(a\) 排序,cdq 就行。

posted @ 2025-05-04 20:08  天域_awa  阅读(81)  评论(0)    收藏  举报