线段树总结

来源:互联网 发布:淘宝货款什么时候解冻 编辑:程序博客网 时间:2024/05/16 06:30

初识线段树,线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶子节点。使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度O(logN)。而未优化的时间复杂度为2N,因此有时需要离散化让空间压缩。

对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。

线段树基本操作: 

建立一个结构体

struct
{
int l,r,sum;
}t[140000];
int summ;

定义线段树的构造函数:

void make(int left,int right,int num)//创建线段树     {    t[num].l=left;    t[num].r=right;    if(left==right)        t[num].sum=r[left];    else    {        make(left,(left+right)/2,num+num);        make((left+right)/2+1,right,num+num+1);        t[num].sum=t[num+num].sum+t[num+num+1].sum;    }}

查询:

void query(int left,int right,int num)//查找范围内父节点的和  {    if(left<=t[num].l&&right>=t[num].r)        SUM+=t[num].sum;    else    {        if(right<=(t[num].l+t[num].r)/2)            query(left,right,num+num);        else if(left>=(t[num].l+t[num].r)/2+1)            query(left,right,num+num+1);        else        {            query(left,right,num+num);            query(left,right,num+num+1);        }    }}

添加:

void add(int x,int y,int num)//修改每一个包括改变的那个数的节点 {    t[num].sum+=y;    if(t[num].l==t[num].r)        return ;    if(x>(t[num].l+t[num].r)/2)        add(x,y,num+num+1);    else        add(x,y,num+num);}

减少:

void sup(int x,int y,int num){    t[num].sum-=y;    if(t[num].l==t[num].r)return ;    if(x>(t[num].l+t[num].r)/2)        sup(x,y,num+num+1);    else        sup(x,y,num+num);}