• [HDU5709]Claris Loves Painting(动态开点线段树+合并)


    题意:有n(<=1e5)个点的树,每个点都有颜色(颜色可能重复),有m(<=1e5)个询问,每次询问(x,d)问在x的子树中,与x的距离不超过d的节点有多少种不同的颜色。强制要求在线。

    分析:

      Part A:先考虑颜色不重复的

      如果我们能把每个节点的子树信息建成以深度作为下标的线段树,那么就能很简单地应付查询了

      这个信息也很明显,就是下标表示深度,权值表示该深度的节点有多少种不同颜色(注意我们先考虑颜色没有重复的)

      那么我们可以先对每个节点自己建一个权值线段树,把自己对应深度的那个位置放个1,其它位置放0

      从底向上合并线段树,那么我们就可以得到表示每个节点子树的线段树辣!

      但是每个点暴力开线段树是肯定MLE的

      这个时候我们发现我们建的权值线段树只有一个位置是1,其它都是0,受到主席树节约空间的启发,我们最初建线段树的时候只需要建logn的空间(也就是一边)

      然后合并的时候也类似主席树的那样,有信息更新的节点就重新开个节点来表示,否则直接利用原来建过的节点

      分析一下复杂度,对于n个点,初始建logn的线段树,是O(nlogn)的

      那合并呢?考虑均摊,对于有k个值不是0的一颗线段树,均摊地认为它节点个数是Ck的,而不是Cklogn,那么一路合并上去,就是O(nlogn)的时间(虽然常数有点大)

      ok这都是可以接受的,但是很显然我们这种做法对于同种颜色会重复叠加,那么如何处理呢?

      Part B

      在处理序列里这种颜色重复问题时候,以前都是弄一个pre[x]表示该位置前面的一个同颜色的节点的位置,但这在树上就不适用了,但是可以类比,树上的顺序关系肯定就是深度的大小;而且这题需要合并,那就不能直接用数组记录,需要用线段树处理合并。

      方法是对每个点再建一个线段树,下标表示颜色(1..n),权值表示该颜色在当前子树中出现的最小深度是多少

      同样从叶子节点开始向上合并,合并的时候也是同样将两棵树一直合并到叶子节点,两边取个min就行了

      关键是这是怎样修正我们的答案的呢?

      我们对这第二棵线段树维护到叶节点的时候,这说明我们在合并我们当前的第一棵颜色的时候,当前颜色多算了,那么就把这个max的深度作为下标在第一棵线段树中减掉

      那么减掉多少呢?

      实际上就是减1,因为自底向上,一直保持这样的操作,那么每次多加的次数一定就是1,所以减掉的次数也是1

      注意更新第一棵线段树中的值的时候,也要动态开辟新的节点

      复杂度也是O(nlogn)的

      因为每次修改/合并都要开辟logn的节点,所以整个需要的空间大概是2*m*(3*logn)

      这样的空间是不会爆的,当然也可以类似主席树的那种对下标进行重回收(还记得大明湖畔的zoj2112吗)

  • 相关阅读:
    HTML5之viewport使用
    css position小结
    图片预加载
    ie6 双边距问题
    json化的必要性
    nginx配置详解(转)
    nginx技术分享 (转)
    js 解决图片居中问题
    NGUI panel使用soft clip时,屏幕缩放后无法正常工作的问题解决
    使用代码修改camera.cullingMask
  • 原文地址:https://www.cnblogs.com/wmrv587/p/6810198.html
Copyright © 2020-2023  润新知