11/4
$2^k$ 个集合,每次标记一个集合的所有子集,可以在 $O(k2^k)$ 内完成。
两个序列,$a$ 单调递增,$b$ 单调递减,求 $\min(\max(ai,bi))$,用二分法。
priority_queue 的仿函数不要使用全局变量,否则可能出现莫名其妙的错误。把比较内容全部写在结构体中。
当要在 $n$ 个 vector 中询问多次 lower_bound 时,可以考虑对于前几个 vector 预处理前缀和优化。
11/5
对于一个有 $n$ 个数的序列 $a$ 满足 $|ai| \leq W$,可以在每个元素前加上±号,使得和的绝对值 $\leq W$。
对于一个只有 bool 值的 dp 方程,可以考虑用 bitset 优化。
11/6
用 Dijikstra 求最短路树时,如果随后要判断一条边是不是树边,一定要记得保存边的编号而不是 `fa[u]!=v && fa[v]!=u`,否则会无法处理重边的情况。
同理,对于任何一道题,如果题目中没有明确写没有重边,则判断一条边时,一定要用编号而不是两个端点判断。
最小费用最大流可以用 Dinic 加速但是会很长。并且在求解网络流时尽量合并重边,省很多时间不知道为什么。
1. 当计算满足 $f(x)=i$ 的 $f(x)$ 个数时,可以先求出满足 $i|f(x)$ 的 $f(x)$ 个数,然后用 Dirichlet 差分(本质上就是一个容斥)。
2. 如果一个算法时间复杂度为 $O(n*\sum{i})$ 之类的,可以考虑阈值划分,即对于 $i \leq B$ 采取以上算法,对于 $i>B$ 采取另一种算法。
如果题目要求一个区间内前 $m$ 大或第 $m$ 大的数的一个函数,可以考虑维护一个链表,每次找到那个第 $m$ 大的数,并向左向右“扩张” $m$ 个数即可。
树链剖分可以作为树形 dp 的一个有效方式,方法为递归重链&轻子树(即从重链上长出来的子树)。
想用二分法,当值域过大时,可以改为随机找出一个,通过比它大的有几个来判断二分递归。
求一个区间内是否存在一个数出现奇数次,可以对每个数赋一个很大的随机权值,然后求区间异或和,若异或和不为0则一定有出现奇数次的数,反之则可以认为没有。
求一个集合,可以想办法找到另一个集合,使之与原集合成一一对应,证明不重不漏即可。
11/7
1. 对于集合的树上两两合并,不用惊慌,用启发式合并,并且记得是 swap(mp[x],mp[y]) 而不是 swap(x,y),神奇的是,map 的 swap 操作是线性的。
2. 当动态/静态统计一个区间内所有数各不相同时,可以考虑开一个 map,然后 mp.size()==len 时即所有数各不相同。注意当 (--mp[x])==0 时要 mp.erase(x)。
3. 动态/静态统计一个区间内所有数各不相同,也可以通过记录 $lst_i$ 为每个位置 $i$ 上一个与该位置上的数相同的位置,则一个区间 $[l,r]$ 内所有数各不相同等价于 $\max_{l \leq i \leq r} lst_i < l$。
$lst_i$ 可以用一棵线段树动态维护。(但是本题似乎会因常数大而T掉)
1. $k$ 较小时最好能够预处理 $2^k$,省掉那个 $\log mod$(
2. 性质:对于树上任意一条直径 x—y 与任意一个点 u,令 $d=\max(dis(u,x),dis(u,y))$,则对于树上任意另外一个点 v,有 $dis(u,v) \leq d$。
证明:考虑 u 到直径的距离即可。