OI 中一些可能有用的小 Trick 与注意点

持续更新,但是更新周期会比较长。


图论:

杂项:

  1. 树上边权转点权转移到儿子节点,但是特别注意多余信息处理(尤其是树剖的时候)
    比如树剖结束的时候处理最后一条重链,最顶端节点的答案不能处理进去(因为会有多余信息 ( t o p x , f a t o p x ) (top_x,fa_{top_x}) (topx,fatopx)
    还有一些计数题比如说统计路径上有多少个不同颜色的,注意一下根节点的多余数据处理(因为根节点是没有颜色的)。
  2. 看到图论题先想一下这几个问题:图是否连通?有向图还是无向图?是否带权?有没有重边与自环?
  3. 遇到矩阵问题不要老是想和矩阵有关的算法,有些时候或许只是道简单的图论。可能每个点是一个点,也可能一列一行是一个点,都有可能。
  4. 看清楚是有向图还是无向图,无向图空间要开 2 倍!网络流的边数与点数不能算错!
  5. 缩点的时候注意不能将原图和新图搞错。
  6. 如果需要使用各种 连通块内的算法(比如最短路,网络流等等),无论图是否连通,最好建立 虚拟起点/虚拟终点(网络流有个词叫 超源超汇),强制使这张图变为连通图。
  7. 无论做什么题目,如果需要建图,一定要注意 边权是否有意义!
    比如说 P3275 [SCOI2011]糖果,利用差分约束建图时,如果采用最短路建图,就会出现 ( b , a , − 1 ) (b,a,-1) (b,a,1) 这样的边,但是糖果数显然非负,因此边权无意义,答案错误。
  8. 树的直径有一个很好的性质:
    如果一棵树的直径长度为偶数,那么这棵树的所有直径一定交于一点,并且这个点是直径的中点;
    如果一棵树的直径长度为奇数,那么这棵树的所有直径一定交于一边,并且这条边的中点是直径的中点。

网络流:

  1. 网络流中拆点是很常见的一种技巧。例题
  2. 网络流中计算点数的时候注意不要忘记 拆出来的点与超源超汇,在采用当前弧优化的时候这些点也是需要算进去的。
  3. 网络流中出现阶段性问题的时候(比如时间),一般就是分层图上的网络流问题,此时算好 点数与边数的极限上界并且不要采用 ISAP 求解最大流(直接二分答案除外),因为 dinic 可以直接在新图的残量网络上跑。例题

数据结构:

  1. 数据结构题不要只想 log ⁡ \log log 结构,分块它不香吗?根号分治它不香吗? 莫队它不香吗?
  2. 有些 DS 题会问你一个区间 [ l , r ] [l,r] [l,r] 内需要划分成至少几个子序列以满足题意,比如这道题,这个时候有一种思路就是先双指针处理出每个点往右边能够预处理的最右点,然后倍增即可。
  3. FHQ Treap 在处理区间信息的时候如果需要维护懒标记的时候需要注意 Merge() 函数中 x,y 都需要下传懒标记。典型例题

DP:

  1. 遇到类似于 n n n 个东西分成两组,差最小等问题,不要总是想着一些奇奇怪怪的算法,如果就是个容量为 n 2 \dfrac{n}{2} 2n 的背包问题呢? 此时的体积和价值都是这 n n n 个东西的属性。
  2. 如果发现题目是个 O ( n 2 ) O(n^2) O(n2) 的 DP,别多想,状态只能是 f i , j ( 1 ≤ i , j ≤ n ) f_{i,j}(1 \leq i,j \leq n) fi,j(1i,jn) 或者是 f i f_i fi(1D/1D 的 DP,不过这个一般能优化到 O ( n ) O(n) O(n))。

数学/数论:

  1. 对于一张无向图的邻接矩阵而言,如果 A i , j A_{i,j} Ai,j 表示 i i i j j j 之间是否有连边,那么做矩阵快速幂 A k A^k Ak 之后 A i , j A_{i,j} Ai,j 的值表示从 i i i 出发走 k k k 步有多少方案到 j j j
  2. 看到异或问题首先就是要想到线性基,其次就是要想到 a ⊕ b = a ∣ b − a & b a \oplus b=a \mid b - a \& b ab=aba&b,因为这样就可以通过处理线性基/或+与的手段解决异或问题。
    当然不要忘记二进制问题可以拆位处理。

小技巧:

  1. 遇到区间问题多想想差分,尤其是树上差分。
  2. 类根号分治思想真的是非常常见又好用的一种思想!

杂项

  1. 关于优先队列的重载运算符问题:
    注意优先队列是一个大根堆,因此重载小于号的时候如果重载函数里面写的是 f i r . a < s e c . a fir.a < sec.a fir.a<sec.a,这表示 f i r fir fir s e c sec sec 小,因此 s e c sec sec 要排到前面。
    就像这样:
    struct cmp
    {
    	int x, y;
    	bool operator <(const cmp &fir) const
    	{
        	return y > fir.y;
    	}
    };
    
    假设要比较的是 a < b a<b a<b,要使优先队列里面 y y y 为第一关键字升序排序,就需要根据大根堆的性质重载小于号为大于号话说怎么这么绕,这样才能够保证 a . y < b . y a.y<b.y a.y<b.y 的时候 a a a b b b 前面。
  2. Meet in meddle,二分 / 三分,启发式合并,倍增等算法别忘了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值