zoukankan      html  css  js  c++  java
  • 【知识总结】线段树合并及其复杂度证明

    应该算是比较基础的知识了吧 …… 随便写写,主要内容是证明。

    例题(现编的):有一棵 (m) 个点的有根树,每个点上有若干个数,(m) 个点上共有 (n) 个数,数的规模是 (N) 。每次询问给定 (u,l,r) ,求 (u) 的子树中有多少个数在 ([l,r]) 中。

    做法是每个点开一棵线段树,插入这个结点上的数。如果能把一个结点的线段树的信息在合理的时间内全部插入(或者说「合并」)到它父亲的线段树中,就可以由下往上做一遍树上递推,这样每个结点的线段树都存储的是整棵子树的信息了。

    先放代码吧:

    int merge(const int x, const int y)
    {
    	if (!x || !y)
    		return x + y;
    	int a = ++cnt;
    	tree[a].sum = tree[x].sum + tree[y].sum;
    	tree[a].lt = merge(tree[x].lt, tree[y].lt);
    	tree[a].rt = merge(tree[x].rt, tree[y].rt);
    	return a;
    }
    

    这个代码还是相当好理解的,无需赘述。下面来证明一下复杂度。(我想了一中午终于想出一个超简洁的证明 —— 本来以为会很复杂的)

    从代码中可以看出合并两棵树的复杂度约等于这两棵树 重合 的结点数。也就是说,每次合并的复杂度不会超过较小的那棵的点数。既然如此,总复杂度就不会超过总点数,也就是 (O(nlog N)) 。而访问到一个结点才会新开一个结点,所以空间复杂度也是 (O(nlog N)) 。实际操作中可能空间有两倍的常数。

    哇怎么这么短就写完了 ……

  • 相关阅读:
    Mac 下安装Ant
    MAMP 10.10下启动报错解决方案
    [转]常用iOS图片处理方法
    Mac下Android SDK更新不了的解决办法
    细说23+1种设计模式
    mysql应该了解的知识点
    java快排思想
    简介一下 i++和++i&&i=i+i,i+=1;的区别
    对int类型的数据,如何让获取长度
    第一次写博客
  • 原文地址:https://www.cnblogs.com/zyt1253679098/p/12059979.html
Copyright © 2011-2022 走看看