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