线段树简述

来源:互联网 发布:linux压缩成zip 编辑:程序博客网 时间:2024/06/08 20:09
线段树是一棵二叉搜索树,常用于解决区间问题。

线段树每一个非叶子节点[left,right],它的左二子区间[left,(left+right)/2],右儿子区间[(left+right)/2+1,right]。

线段树的结构体,内元素包括,此节点包含区间[left,right],和value

    //线段树结构体      #include <bits/stdc++.h>      using namespace std;      const int maxn = 1<<20;      const int N;      struct Node {          int value;   //检点区间权值          int left, right;  //区间(left,right)      }node[maxn];      int father[N];  //每个点(当区间长度为0时,对应的结构体数组下标)  

线段树的建立

    void BuildTree(int i, int left, int right)      {          node[i].left = left;  //写入第i个结点的左区间          node[i].right = right;  //写入第i个结点的右区间          node[i].value = 0;  //区间权值初始化为0          if(left == right) {              father[left] = i;  //知道每个点对应的序号(结点的下标)              return;          }          //建立左子树          BuildTree(i<<1, left, (left+right)/2);          //建立右子树          BuildTree((i<<1)+1, (left+right)/2+1, right);      }  

单点更新线段树

因为事先用father[]数组保存过每个节点对应的的下标,因此只要知道第几个点,就知道这个点在树中的位置(即下标),这样就只要一路向上更新上去即可。


    void UpdateTree(int r1)      {          if(r1 == 1) return;   //已找到祖先          int fi = r1/2;          //ri的父节点          int a = node[fi<<1].value;   //该父节点的两个孩子          int b = node[(fi<<1)+1].value;  //右          node[fi].value = (a > b) ? a : b;          UpdateTree(ri/2);  //递归更新,有父节点往上找      }  

查询区间最大值

讲一段区间从上往下拆开,直到存在有完全重合的区间停止。

    int Max = -1<<20;      void Query(int i, int l, int r)      {          if(node[i].left == l && node[i].right == r) {              Max = (Max < node[i].value) ? (node[i].value) : (Max);              return;          }          i = i << 1;          if(l <= node[i].right) {    //左区间有涉及              if(r <= node[i].right)   //全包含于左区间,则查询形态不变                  Query(i, l, r);              else          //半包含于左区间,则查询区间拆分,左端点不变,右端点变为左区间的右孩子端点                  Query(i, l, node[i].right);          }          i += 1;          if(r >= node[i].left) {    //右区间有涉及              if(l >= node[i].left)  //全包含于右区间,则查询形态不变                  Query(i, l, r);              else        //半包含于右区间,则查询区间拆分                  Query(i, node[i].left, r);          }      }  



原创粉丝点击