线段树学习

来源:互联网 发布:环境污染数据表格 编辑:程序博客网 时间:2024/06/16 14:34

参考两位神犇的博客:
https://www.cnblogs.com/TenosDoIt/p/3453089.html
https://www.cnblogs.com/TheRoadToTheGold/p/6254255.html
好吧终于学了线段树,核心思想是二分,然后构建一个完全二叉树,根节点表示区间[l,r],左儿子表示区间[l,mid],右儿子表示区间[mid+1,r],叶节点l==r。
每个节点可以存区间和,区间最值。
预处理时间O(n),查询时间O(logn),更新时间O(logn),需要额外的空间O(n)。
讲道理还是蛮好理解的,懒标记做区间修改待更新。。。

//线段树模板//此模板为维护区间和的线段树为例struct node{    int l,r,w;//l,r分别表示区间左右端点,w表示区间和}tree[4*n+1];//结构体要开4倍空间//建树//l:左端点;r:右端点;root:当前根节点的下标void build(int l,int r,int root){    tree[root].l=l;tree[root].r=r;    if(l==r)        tree[root].w=arr[l];    else    {        int mid=(l+r)/2;        build(l,mid,root*2);//递归构造左子树        build(mid+1,r,root*2+1);//递归构造右子树        tree[root].w=tree[k*2].w+tree[k*2+1].w;//根据左右子树根节点的值,更新当前根节点的值    }}//单点查询//单点查询的思路就是二分//区间查询//区间查询的思想是选出一些区间,使他们相连后恰好涵盖整个查询区间,因此线段树适合解决“相邻的区间的信息可以被合并成两个区间的并区间的信息”的问题。//以查询[x,y]的区间和为例int query(int k){    if(tree[k].l>=x&&tree[k].r<=y)     {        ans+=tree[k].w;//当前区间被完全包含在[x,y]中,直接加上        return;    }    int m=(tree[k].l+tree[k].r)/2;    if(x<=m) sum(k*2);//当前区间的左半边与[x,y]有重合,则递归查询左子树    if(y>m) sum(k*2+1);//当前区间的右半边与[x,y]有重合,则递归查询右子树}//单点修改//单点修改的思路是找到二分x的位置,根据建树原理,修改每个节点//以给第k个数加y为例void add(int k){    if(tree[k].l==tree[k].r)    {        tree[k].w+=y;        return ;    }    int m=(tree[k].l+tree[k].r)/2;    if(x<=m) add(k*2);    else add(k*2+1);    tree[k].w=tree[k*2].w+tree[k*2+1].w;//将所有包含k节点的区间更新}//区间修改///**/
原创粉丝点击