板子
数据结构
单调栈/队列
并查集
ST表
线段树
珂朵莉树
图论
存储
链式前向星
vec型
1234567vector<int> nxt,head,to;//初始化 head.resize(n+1,-1)void add(int u,int v){ nxt.push_back(head[u]); head[u] = to.size(); to.push_back(v);}
数组型
12345678const int N=1e5;int nxt[N],head[N],to[N];int cnt = 0;void add(int u,int v){ nst[++cnt] = head[u]; head[u] = cnt; to[cnt] = v;}
判断二分图
数学
高精度
快速幂
若无需模,请无视 \(p\)
123456789int qpow(int a,int b,int p){ int res = 1; while(b)& ...
各题型题解
p {
text-indent: 2em;
}
算法基础
贪心
模拟
枚举
分治
排序
二分
P1182 数列分段
Section II - 洛谷
二分答案
构造
倍增
前缀和/差分
1526.
形成目标数组的子数组最少增加次数 - 力扣(LeetCode)
题目大意
问对初始全为0的序列,如果每次仅允许对[l,r]区间的所有元素加1,那么求出得到target数组的最少操作次数
我们知道对差分数组作前缀和能得到原数组。由于 target
是通过 \([l,r]\) 区间元素加 \(1\) 得到的,target 的差分数组
diff 显然记录了这样的过程:
每次 \([l,r]\) 操作对应 \(diff[l]+1\) 、 \(diff[r+1]-1\)
在操作结束后,对 diff 作前缀和操作,得到
target
我们要做的显然就是 “溯源”。
事实上,最少操作次数为其差分数组中正整数之和。
证明
显然正整数是操作的痕迹 ...
下列OJ平台仅代表题目信息的一个出处,不一定为OJ平台原创
每道题下面的均为其中关键的解题思路,题目大意并非完整题目,只出现解题思路中需要的变量。
(因此,基于测试用例t等无关变量将不会出现)
各题出处如下:
Codeforces
洛谷
力扣
码蹄集OJ(百度)
蓝桥杯
其他
Codeforces
Cherry Bomb
Codeforces Round 1020 div.3 C. Cherry Bomb Problem - C -
Codeforces
tags: greedy math sortings *1000
题目大意
两个非负整数数组a与b,当我们称其互补时,当且仅当对于每个编号i,均有ai+bi= x, 其中x为一定值。我们希望数组a,b的每个元素均非负且不大于k,并且a与b是互补的。接下来,会给出n和k、完整的数组a,以及不完整的数组b,不完整的地方用-1补齐,请问有多少种填充b的办法满足我们的需要。
核心是如何确定互补值的值域,或者minb、maxb的值域
Fa ...
参考资料:树形 DP - OI
Wiki
树形DP
树形 DP,即在树上进行的DP。由于树固有的递归性质,一般通过递归DFS(或
BFS) 进行
基础
P1352
没有上司的舞会 - 洛谷
某大学有 \(n\) 个职员,编号为 \(1\ldots n\)。
他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。
现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 \(r_i\),但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。
所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
不妨设 \(f(i,0/1)\) 表示以 \(i\) 为根的子树当其根节点的值
取/不取 的最优解( \(0\) 表示 \(i\) 不去舞会,反之要去)
对于每个状态,都存在两种决策(以下 \(x\) 为 \(i\) 的所有儿子)
上司不参加舞会时,下属可以参加,也可以不参加,是否参加取决于所能产生的最大快乐值,因此有
\[
f(i,0) = ...
前缀和、差分、离散化
参考资料:
前缀和 & 差分 -
OI Wiki
离散化 - OI Wiki
前缀和
数列前 \(n\)
项的和,是一种重要的预处理方式。
一维前缀和
可得到其递推式\(S_0=0,S_i =
S_{i-1}+a_i\)
作一维前缀和数组 \(ps\),其中下标i表示前 \(i\) 项的和
对区间[l,r]求和,显然用 \(ps[r]-ps[l-1]\) 即可,时间复杂度为 \(O(1)\)
二维/多维前缀和
将一维前缀和扩展到多维的情形。其常见的求解方法有两种
基于容斥原理
多用于二维前缀和的情形。给定大小为 \(m\times n\) 的二维数组 \(A\) ,要求求出其前缀和 \(S\)。那么,\(S\) 同样是大小为 \(m\times n\) 的二维数组,且
\[S_{i,j} = \sum\limits_{i'\leq{i}
}\sum\limits_{j'\leq{j}}A_{i'j'}\]
显然,对于 \(S_{i,j}\),我们可以通过容斥原理获得:
\[S_ ...
双指针
引入
双指针是一种简单而又灵活的技巧和思想
,单独使用可以轻松解决特定问题,和其他算法结合也能发挥多样的用途。
双指针顾名思义,就是同时使用两个指针,在序列、链表结构上指向的是位置,在树、图结构中指向的是节点,通过或同向移动,或相向移动来维护、统计信息。
维护区间信息
如果不和其他数据结构结合使用,双指针维护区间信息的最简单模式就是维护具有一定单调性,新增和删去一个元素都很方便处理的信息,就比如正数的和、正整数的积等等。
例题1
713.
乘积小于 K 的子数组 - 力扣(LeetCode)
给定一个长度为 \(n\) 的正整数数组
\(nums\) 和整数 \(k\) ,找出该数组内乘积小于 \(k\) 的连续子数组的个数。
过程
设两个指针分别为 \(l,r\)
,另外一个变量 \(tmp\) 记录 \([l,r]\) 内所有数的乘积。最开始 \(l,r\) 都在最左面,先向右移动 \(r\) ,直到第一次发现 \(tmp \geq k\) ,这时就固定 \(r\) ,右移 \(l\) ,直到
神技
记录网上看到的,泛用性较强的解题神技,持续更新
前缀“乘”
713.
乘积小于 K 的子数组 - 力扣(LeetCode)
往往前缀和,当用乘法表示加和时,是会很容易爆ll的,那么,我们可以通过
\(log\)
对数将乘法转换成加法,把之转化成真正的前缀“和“。尽管,我们无法得到精确的值,但用来作为条件判断已经足够了
前缀和求解转化为
$ ps[i] = ps[i-1]+log(nums[i])$
求 \([l,r]\) 的乘积小于 \(k\) 可表示为
\(ps[m]-ps[i-1]+10^{-10}<logk\)
double 类型只能保证 \(15\)
位有效数字是精确的。为了避免计算带来的误差,相减后要加上 \(10^{-10}\)(题目中的 double
数值整数部分的数字不超过 5 个)
,从而防止不等式两边数值相等却被判定为大于的情况。
珂朵莉树
参考资料: 珂朵莉树/颜色段均摊
- OI Wiki
珂朵莉树(Chtholly Tree),又称ODT。源自 CF896C。
这个名称指代的是一种使用 平衡树 或
链表
维护「颜色段均摊」的技巧,而不是一种特定的数据结构。其核心思想是将指相同的一段区间合并成一个结点处理。相较于传统的线段树等数据结构,对于含有区间覆盖的操作问题,珂朵莉树可以更加方便地维护每个被覆盖区间的值。
实现(std::set)
结点类型
123456struct Node_t{ int l,r; mutable int v; //mutable能突破 const 的限制,使变量永远可变 Node_t(const int &il,const int &ir,const int &iv):l(il),r(ir),v(iv){} //构造函数 bool operator<(const Node_t &o) const {return l<o.l;}};
...
归并排序
定义
归并排序(merge sort)是高效的基于比较的稳定排序算法
性质
归并排序基于分治思想将数组分段排序后合并,时间复杂度在最优、最坏与平均情况下均为
\(O(nlogn)\),空间复杂度为 \(O(n)\)。
归并排序可以只使用 \(O(1)\)
的辅助空间,但为便捷通常使用与原数组等长的辅助数组。
过程
合并
归并排序最核心的部分是 合并(merge)过程:将两个有序的数组 \(a[i]\) 和 \(b[i]\) 合并为一个有序数组 \(c[k]\)。
从左往右枚举 \(a[i]\) 和 \(b[j]\),找出最小的值并放入数组 \(c[k]\);重复上述过程直到 \(a[i]\) 和 \(b[j]\)
有一个为空时,将另一个数组剩下的元素放入 \(c[k]\) 。
为保证排序的稳定性,前段首元素小于或等于后端首元素时(\(a[i]\leq b[j]\))而非小于时(\(a<b\)),就要作为最小值放入 \(c[k]\)
数组实现:
12345678910111213141516void merge(const int *a, i ...
参考资料:倍增 -
OI Wiki
倍增
定义
倍增法(binary
lifting),即“成倍增长”的含义。我们在进行递推时,如果状态空间很大,那么通常的线性递推无法满足空间和时间复杂度的要求。那么,我们可以通过成倍增长的方式,只递推状态空间中在
\(k\)
的整数次幂位置上的值作为代表。当需要其他位置上的值时,我们通过k的一元多项式之和得到。所以使用倍增算法也要求我们递推的问题的状态空间关于
\(k\) 的次幂具有可划分性。通常情况下
\(k\) 取 \(2\) (这样每项的系数要么为 \(1\) ,要么为 \(0\) )
应用
RMQ问题
RMQ 是 Range Maximum/Minimum Query
的缩写,表示区间最大(最小)值 。使用 ST表
是基于倍增思想的 RMQ问题 求解方式
树上倍增求LCA
求最近公共祖先的倍增解决方式







![算法板子[updating]](/./images/2025-11-20/baka3.png)
![各题型题解[updating]](https://ooo.0x0.ooo/2025/05/25/OdQPQl.png?_r_=da728f1f-eef3-c164-9c54-942c4c9805a9)



