线段树总结

初识线段树,线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶子节点。使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度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);
}
原文地址:https://www.cnblogs.com/nanfenggu/p/7900073.html