2017年10月8日训练总结

时间:2021-01-28 14:27:35

这次训练总结是国庆八天。

对树状数组在一些的难一点的题目中的运用又有了新的认识和感悟。

首先是对于树状数组的离线处理有了一定的了解,并在求区间不重复数字个数和出现2次数字个数能够快速正确的写出AC代码。然而浪费了3天时间在想其他题目上,结果一道也没想出来,最后还是先去做树状数组专题的题目。另一方面看了求区间GCD个数的博客,学会了用vector<pair<int,int> >存gcd和它出现的位置,再离线处理,将询问排序。但是在做求区间最大GCD的时候,用了一个技巧,就是答案一定是某个数的因子。因此先把所有的因子都记录下来并用vector<int> vc[mx]存它是哪个数的第几个因子。离线之后枚举每个a[i],如果一个因子出现了两次就说明区间内有两个数的gcd是它,加入树状数组中,询问的区间按右端点升序排序,然后用树状数组维护区间最大值(第二次用树状数组维护区间最大值,第一次是求最长不下降子序列的时候),右端点等于i的时候从左端点往上找最大值即可。

另外做的一道题是魔法球游戏。就是给一棵树,1为根节点,每个节点都有权重,每个节点有左右孩子或者没有。一个球到每一个节点往左走还是往右走取决于球的重量和节点的权重。询问球经过某个点的概率。输出7的多少次方除以2的多少次方。如果不可能经过某个点就输出0。

思路:由于对于每个询问都唯一确定一条路径,用树状数组+搜索遍历整棵树并求解。用树状数组存哪个位置的数比它大。用树状组分别询问球重量所在位置的上下即可求出到达改点的路径里有几个比它打的和比他小的左子树和右子树。如果该路径上比它小的点和比它大的点个数和不等于总个数,那就是在它之前就停下了,记录0。用一个二维数组保存结果即可。此处用的是树状数组的回溯。。。

树状数组专题练习题中最后做的一道就是给一棵树,1为根节点,求以i为根节点的子树有多少个正好出现k次的数字。刚开始读了半天没读懂题,好不容易读懂了题意也是毫无思路。最后也是看了题解的思路,才知道把树化成一维数组,把询问的子树化成询问区间。

思路:先用hash把每个点的权值离散化,把要问的子树利用深搜化成区间,把所有的点重新排列到一维数组中记录该点的权值,记录每个要求的点的初位置和末位置即为区间左右端点。这样就变成了求子区间出现k次的数字个数。再用树状数组离线的方法,把每个区间按右端点升序排序,从第一个点开始,用数组记录权值为a[i]的点到目前为止出现了几次。若出现的次数大于等于k次,就在这个重量出现的次数-k的位置加1,若出现次数大于k次,就在就在这个重量出现的次数-k-1的位置加-2(-2而不是-1是因为如果询问的区间左端点小于那个点,那这个点的权值出现的次数就大于了k次,不应该算到结果里,于是再减一)。这样就保证了每一次询问的区间得到的都是出现k次的数的数量。然后i等于右端点的话就直接query(r)-query(l-1)就行了。在这里我用hash定义hash函数来离散化权重,但是交了4次ce,查了好久才知道hash是关键字,直接定义函数就会ce。。。看来以后hash的时候要注意了。

树状数组的专题总算做完了,也学到很多新用法,但是再遇到难度差不多的题应该还得费不少力气。。。以后在遇到的时候一定要清掉。

做了好久树状数组,线段树也快忘了。重新看课件,开始做线段树专题的题目。(国庆专题的题目有点难。。。暂时放弃了)还有大约10天的时间。抓紧时间把线段树题目刷一下,然后再看看KMP的有关知识。。。