学习总结1

来源:互联网 发布:软件测试的基本原则 编辑:程序博客网 时间:2024/06/05 12:48

2017-12-1 点分治+伸展树学习

点分治

点分治主要用来处理一些和树上路径相关的问题。对于一棵树,如果要统计满足某种条件的路径的条数,可以O(n2)枚举所有可能路径并判断是否合法,但是这样做在数据规模较大时可能无法承受,这时就需要使用点分治了。
点分治的大致做法是先一遍DFS找到树的重心,然后以重心为根,递归统计每一个子树的答案,再考虑包含根节点的路径。因为以重心为根时,每次递归后树的节点总数都不会大于原先的一半,所以至多递归logn层,就在更短的时间内完成了对一棵树所有路径的统计。

例题

POJ1741 Tree

询问树上距离不超过k的顶点对数。经典的点分治入门题。此题需要注意如何高效地统计包含根节点的路径,可以把所有节点深度排序后扫一遍统计并去重,也可直接使用平衡树统计。每次统计复杂度为O(nlogn),总复杂度O(nlog2n)

bzoj2599 [IOI2011]Race

记录一个当前到根节点边权和为某个值的所有节点最小的深度值即可。

bzoj2152 聪聪可可

求一棵树上边权和是3的倍数的路径条数。可以记录每个子树中长度除以3余0,1,2的路径条数。当然这道题也可以用树形DP解决。

hdu4812 D Tree

给一棵树,点带权。问是否存在一条路径使所有点的权值乘积模106+3K,若有解,还需输出字典序最小的路径两端点编号。注意到106+3是质数,于是可以预处理逆元,统计就很简单了。

CDOJ1562 Amaz1ng Prime

给定一棵树,边权为0或1,问边权之和为素数的路径条数。此题在点分治的过程中难以统计答案,可以考虑先通过点分治求出一个num数组,其中num[i]表示树上权值之和为i的路径数,再统计答案。于是问题转化为如何快速统计num数组。经过冷静分析,发现每次统计经过根的路径时有num[x]=xi=0f[i]f[xi]再减去算重的。前者是一个卷积的形式,暴力计算无法承受,可以用FFT加速。

bzoj3697 采药人的路径

给一棵树,边权为1或-1,问树上有多少条路径满足边权和为零,且存在一个中间点,使得该点到路径两个端点的边权和都为零。此题比较复杂,需要对点分治的过程有深刻理解。具体地说,每次用一遍dfs记录所有的点以当前根为起点的前缀和作为点的权值。如果存在一个当前点到根的路径中的点,满足其权值和当前点的权值相等,就这个点标记为已经存在中间点。于是用数组num[i]记录权值为i的点数,分情况统计。

Osipovsky Cup 2014 Problem A. Attack and Defence

给一棵树,每个点上有一个左括号或者右括号,问树上能够构成合法括号序列的路径数量。本题关键在于,如果将一个合法的括号序列分为左右两半,左右两半应当满足什么性质。以左半边为例,一个合法的括号序列的任意一个前缀中右括号的数量都不大于左括号的数量,具体地说,可将左括号视为1,右括号视为-1,那么一个点到重心的路径能作为合法括号序列的左半部分,当且仅当其到中心的前缀和大于等于零,且前缀和的前缀min大于等于零。对于右半边的合法判定也可以类似处理。用数组记录下左右半边合法的数量就可以统计了。

总结

学完点分治又写了写题,感觉点分治最主要的难点是在于统计过重心路径上,这部分不同的题有不同的解决方案,比较灵活。不过这也是有套路可循的,相信多加练习一定能熟练掌握。

伸展树

伸展树是平衡树的一种,它最大的特点是能通过伸展操作灵活的调整形态,将查找频率较高的条目尽量放在靠近根的位置。伸展树空间占用小,可用来维护序列,或是作为LCT的辅助树,各种操作的实现都很方便。其缺点在于常数较大,无法可持久化。
伸展树的核心操作就是伸展操作。伸展树应用很广泛,需要熟练掌握。

例题

bzoj3224 Tyvj 1728 普通平衡树

平衡树模板题。注意一下重复值的处理即可。涉及的操作都比较常用,需要熟记。

bzoj1208 [HNOI2004]宠物收养所

此题的题意没有前一道题直接,但也不难用插入删除前驱后继等基本操作,剩下的就是写板子了。需要注意的是不知道人和宠物哪个更多,可以用两颗平衡树,分别存人和宠物,也可以只用一颗平衡树,再用一个变量,初始为0,来一个人时+1,来一个宠物时-1,根据变量的正负判断平衡树里存的是人还是宠物。

bzoj1861 [Zjoi2006]Book 书架

额外记录下每个位置上书的编号,以及每个编号的书的位置,然后就是写模板了。

bzoj2733 [HNOI2012]永无乡

维护一张点带权无向图,操作有连边和询问某个连通块内的第K小点权是多少。需要用到平衡树启发式合并,即把较小的平衡树中的节点全部插入较大的平衡树。当然也可以用线段树做。

hdu6133 Army Formations

给一颗二叉树,点带权,一个结点的代价被定义为将其子树中所有结点的权值放入数组从大到小排序后,每个权值乘以其下标的和。计算所有结点的代价。同样是splay启发式合并。这道题线段树也可做,但略微卡空间,splay就不会有这个问题。

洛谷3372 【模板】线段树 1

一道线段树入门模板题,可以用来练习splay维护区间信息的写法,包括打标记,标记下放等。

bzoj3223 Tyvj 1729 文艺平衡树

维护序列,支持区间翻转。模板题,打翻转标记即可。

Codeforces Round #424 Div. 1 B. Cards Sorting

给一个序列。一次操作定义为:如果左起第一个数上是所有数中最小的,则删除该数,否则将它移到序列的最右端。重复操作到序列为空。问总共会进行多少次操作。问题不难转化为每次找到序列最小值并删除,同时加上它对答案的贡献。直接用splay模拟这一过程即可。

总结

伸展树的应用十分广泛,是非常重要的一个数据结构,之后一定要熟记模板,勤写多练,争取能在短时间内一遍写出。