本文用来记录我学习算法时的一些灵感和体会

欢迎各位神犇提出见解和指导~如有指正,不胜荣幸~

 


 

图论:

  树链剖分:

    静态树的对确定对象的维护/查询

    UPD:zyf神犇说的吼:树链剖分就是一个特殊的dfs序,玛雅一看构造过程还真是在dfs……只是每次先走子树最大的儿子0.0,所以树链剖分其实也是可以搞子树的……OrzOrzOrz

  点分治:

    静态树上对不确定对象的查询(找经过x个黑点的最长路径)大部分就是找一些东西吧……

    其实点分治的时候只需考虑一种情况:经过【根节点】的路径/方案。剩下的情况递归处理即可。

  朱-刘算法:

    不停找环->缩环的过程,直到没有环了以后直接累加。

  dfs序:

    将树转成序列进行操作,利用dfs时一进一出,保证了任何一条路径都可以用dfs序列上一段连续区间表示(多余部分一进一出自行抵消)

    转成序列后即可使用线段树等数据结构进行维护……

  树分块(块状树):

    dfs时每 根号n 分一块,对于查询(x,y)按belong[x]为第一关键字、belong[y]为第二关键字排序。 

算法笔记_康托展开算法笔记_回文串_02
 1 用S(v, u)代表 v到u的路径上的结点的集合。
 2 
 3   用root来代表根结点,用lca(v, u)来代表v、u的最近公共祖先。
 4 
 5   那么
 6 
 7   S(v, u) = S(root, v) xor S(root, u) xor lca(v, u)
 8 
 9   其中xor是集合的对称差。
10 
11   简单来说就是节点出现两次消掉。
12 
13  
14 
15   lca很讨厌,于是再定义
16 
17   T(v, u) = S(root, v) xor S(root, u)
18 
19   观察将curV移动到targetV前后T(curV, curU)变化:
20 
21   T(curV, curU) = S(root, curV) xor S(root, curU)
22 
23   T(targetV, curU) = S(root, targetV) xor S(root, curU)
24 
25   取对称差:
26   T(curV, curU) xor T(targetV, curU)= (S(root, curV) xor S(root, curU)) xor (S(root, targetV) xor S(root, curU))
27 
28   由于对称差的交换律、结合律:
29 
30   T(curV, curU) xor T(targetV, curU)= S(root, curV) xor S(root, targetV)
31 
32   两边同时xor T(curV, curU):
33 
34   T(targetV, curU)= T(curV, curU) xor S(root, curV) xor S(root, targetV)
35 
36   发现最后两项很爽……哇哈哈
37 
38   T(targetV, curU)= T(curV, curU) xor T(curV, targetV)
39 
40   (有公式恐惧症的不要走啊 T_T)
41 
42  
43 
44   也就是说,更新的时候,xor T(curV, targetV)就行了。
45 
46   即,对curV到targetV路径(除开lca(curV, targetV))上的结点,将它们的存在性取反即可。
【转移】(转自VFK博客)

  虚树:

    当树的规模较大时,我们可以只选出询问到的节点以及他们的LCA们,建立一棵虚树,虚树上的边的信息可以通过倍增求出(同LCA)这样可大大降低时间复杂度

    求虚树的过程是一种模拟DFS的过程,先将所有的询问点按DFN排序,依次处理x与当前栈顶节点的LCA,按照深度关系找出 祖先-后代or兄弟关系 。

   LCT动态维护MST:

    拆边为点,一般将所有边都编一个固定的序号(不妨按权值序)然后为每条边都建一个结点,如果要连(u,v)这条边的时候就连接(u,tmp)和(v,tmp)

  固定标号进行维护,如果修改权值也可直接在新建的结点上修改。

树型DP:

  按序合并子树思想:

    点分治例题FTOUR2中按序枚举子树,并与之前答案合并;以及BZOJ 3611大工程 【依次枚举子树找最长(短)链】这个方法效率很高!


 

数论:

  高斯消元:

    初中学的加减消元的程序化

  霍纳法则:

    参见高中数学课本人教版·必修三 【秦九韶算法】  

  欧拉函数:关键词:互质、最大公约数……(目前看好像是?以后再补充吧……)

  线性同余方程组:

  BSGS:分块的思想!!(莫队……)需要的基础知识:快速幂,逆元/费马小定理(欧拉定理)

    模板题:【BZOJ】【3239】Discrete Logging

        【BZOJ】【2242】【SDOI2011】计算器

  生成函数+FFT算组合数:【BZOJ】【3771】Triple

  莫比乌斯函数&反演:

  Burnside & Pólya:【Burnside定理】&【Pólya定理】


动态规划:

数位DP:预处理和分类讨论是关键= =,合理利用容斥可以反过来求……

插头DP:状态逐格转移,分情况讨论,状态的设计是关键= =好像目前我懂得的就这么点……so sad

四边形不等式:论文的主体思想:w有四边形性质 --> m有四边形性质 --> 转移状态 s 可以限制到一个较小的范围内(降低复杂度 目标达成)

DP优化类型总结


数据结构:

  树套树:在外层的树状数组/线段树中套一个平衡树,可以有效解决许多满足区间加/减法的运算,比如各种前缀和……第k大的数,或是比v大/小的数的和,二维坐标下的前缀和?之类的……见【BZOJ】【3262】陌上花开

  回文自动机:类似AC自动机的东西?我们处理回文子串是否相同的时候,很想用类似字典树的方式来存,但是由于是回文串= =所以不太方便用字典树上的一条链存整个回文串……那么我们可以只存回文串的一半!这样就可以实现在原串的基础上加一个字符来表示另一个回文串了!就可以用字典树来表示了!再结合AC自动机……回文自动机就诞生啦= =(好吧其实还有其他不同)

  可持久化Trie:跟可持久化线段树构造方式很类似?然而记录一下id,查询方式也很类似……?2333

  可持久化并查集:用可持久化线段树维护fa和size的历史版本即可


计算几何:

  然而蒟蒻并不怎么会计算几何……

  先记录一些中学数学知识吧:(QAQ)

  与向量(x,y)垂直的向量有(y,-x)和(-y,x),长度的话自己再搞搞就好了,这个可以拿来搞平行线,然而用的时候要注意方向,一个是左边(向量(y,-x)),一个是右边(向量(-y,x))

  然后是一些算法:

  半平面交:增量算法 $O(n^2)$  维护一个“凸包”,初始为一个大矩形框,然后用直线去截它,截的过程是:依次枚举“凸包”上的每个点,如果在直线左边则将它继续放到新的凸包中,否则就丢掉,同时判断如果连续的两个凸包上的顶点在直线异侧,则说明产生了一个新的交点,要找到这个直线与凸包的交点并加入到新的“凸包”中。

【POJ】【3525】Most Distant Point from the Sea

【POJ】【2068】Art Gallery

  然而半平面交并不一定要用这种做法,有的题目中其实是维护一个单调性,可以直接用斜率维护。

【BZOJ】【1007】【HNOI2008】水平可见直线

【BZOJ】【1038】【ZJOI2008】瞭望塔

  凸包:卷包裹法 $O(nlog(n))$ 算法的瓶颈其实是在排序,所以带了log,然而蒟蒻并不怎么会写……大致嘴巴一下好了:搞出一个水平序,即以x坐标为第一关键字,y坐标为第二关键字,从小到大排序,然后取最左边的点,以它为起始点开始卷包裹,即判断斜率,然后就得到了一个下凸壳;接着再以最右边的点以相同姿势反过来搞一遍,就得到了上凸壳,ok啦~

  进阶版:用数据结构来维护半平面交和凸包,然而蒟蒻并不会……


 

杂记:

  BZOJ 3437:“像这题这种要求“阶梯形求和”的,基本都是利用矩形和$\sum a[i]*i=s[i]*i$ 以及 阶梯形和 $ \sum (a[i]*i) $两种前缀和加加减减拼凑出来的)” 与这题类似的还有POJ 3468(那个区间修改区间求和的数据结构题)

  【BZOJ】【1006】【HNOI2008】神奇的国度:在别人的博客里看到一个总结(原谅我忘了是哪位神犇以及具体内容了):完美消除序列之于弦图 就好似 拓扑序列之于DAG,所以弦图的问题许多都要靠这个完美消除序列来做。

 康托展开:

  康托展开就是一种特殊的hash,且是可逆的……

  康托展开计算的是有多少种排列的字典序比这个小,所以编号应该+1;逆运算同理(-1)。

  序列->序号:(康托展开)

    对于每个数a[i],数比它小的数有多少个在它之前没出现,记为b[i],$ans=1+\sum b[i]* (n-i)!$

  序号->序列:(逆康托展开)

    求第x个排列所对应的序列,先将x-1,然后对于a[i],$\left\lfloor \frac{x}{(n-i)!} \right\rfloor $即为在它之后出现的比它小的数的个数,所以从小到大数一下有几个没出现的数,就知道a[i]是第几个数了。

KD-Tree:

  依次以K维坐标进行折半,一个神奇的Astar= =,估价函数好好设计……重点是处理边界情况!!(好像总是应该专门给0赋一个初值,而不是判断左右儿子是不是0;还有就是query的时候如果遇到0,仔细考虑下这边界情况= =比如【BZOJ】【2626】JZPFAR

  突然发现:KD-Tree是会Push_up叶子节点的!这点跟线段树不一样……算法笔记_康托展开_03怪不得以前写模板的姿势不对……

【BZOJ】【3489】A simple rmq problem:

  因为前面做了两道区域求和的……然后思路不由自主又代入到搞【子树最大值】来更新答案……然而忘记了单点更新,也就是:虽然这个子树不合法,但是这一个点(根)还是可能合法的……

  然后就是:KD-Tree如果可以搞整个子树的话,那么用整个子树的最值去更新,会优化很多……?