转载原地址:https://blog.csdn.net/kerGH/article/details/52291692
线段树是一种简单而实用的算法。
线段树是一棵二叉树,而且是一颗完全二叉树。顾名思义,线段树的每一个节点表示一个区间,如图:
以最大值问题为例:
给你一个数列,每次询问区间最大值是多少。
maketree:
根节点表示1~n的区间最大值,然后将这个区间分成两半,它的两个子节点分别表示这两个区间的最大值,这样我们就可以构造一个线段树。
void maketree(int t,int l,int r)
{
if (l==r)
{
f[t]=a[l];
}
else
{
int mid=(l+r)/2;
maketree(t*2,l,mid);
maketree(t*2+1,mid+1,r);
f[t]=max(f[t*2],f[t*2+1]);
}
}
查询:
我们要一棵线段树有什么用呢?那当然是用来查询的,不然一棵树孤零零的摆在那,你动都不去动它一下那有什么用。
说到查询,相信直接查询一个点,大家都能想到。
就这个图来说,假如要查询的是1~3,该怎么办。
很容易就可以想到,把1~2和3~3这两个区间的最大值合并起来,就可以得到1~3这个区间在最大值。
时间复杂度O(log(n))O(log(n))
code:
int find(int x,int y,int s,int l,int r)
{
if (x==l && y==r)
{
return(max(ans,f[s]));
}
else
{
int mid=(l+r)/2;
if (y<=mid)
{
return(find(x,y,s*2,l,mid));
}
else
{
if (x>=mid+1)
{
return(find(x,y,s*2+1,mid+1,r));
}
else
{
return(max(find(x,mid,s*2,l,mid),find(mid+1,y,s*2+1,mid+1,r)));
}
}
}
}
单点修改:
相信理解了如何建树,那么单点修改就很好理解了。
code:
void change(int x,int y,int t,int l,int r)
{
if (l==r)
{
f[t]=y;
}
else
{
int mid=(l+r)/2;
if (x<=mid)
{
change(x,y,t*2,l,mid);
}
else
{
change(x,y,t*2+1,mid+1,r);
}
f[t]=max(f[t*2],f[t*2+1]);
}
}
区间修改:
待续…………