标签:
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。
因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。
用线段树解题关键是要清楚的知道每个节点要存放什么信息,以及这些节点如何高效的更新,维护,查询,不一定每次都更新到叶子节点,这样复杂度最坏有可能是0(n)
下面附上一道题
poj3264
思路:用一维数组存放节点,节点数<=4n-1,每个节点存放该区间的最大值,最小值
代码
#include<iostream>
#include<stdio.h>
using namespace std;
const int INF=100000000;
int minV=INF;
int maxV=-INF;
int max(int a,int b)
{
return a>b?a:b;
}
int min(int a,int b)
{
return a>b?b:a;
}
//节点信息
struct Note
{
int L,R;
int minV,maxV;
int Mid()
{
return (L+R)/2;
}
};Note tree[800010];
//建树
void buildtree(int root,int L,int R)
{
tree[root].L=L;
tree[root].R=R;
tree[root].minV=INF;
tree[root].maxV=-INF;
if(L!=R)
{
buildtree(root*2+1,L,(L+R)/2);
buildtree(root*2+2,(L+R)/2+1,R);
}
}
//插入
void insert(int root,int i,int v)
{
if(tree[root].L==tree[root].R)
{
tree[root].minV=tree[root].maxV=v;
return ;
}
tree[root].minV=min(v,tree[root].minV);
tree[root].maxV=max(v,tree[root].maxV);
if(i<=tree[root].Mid())
{
insert(2*root+1,i,v);
}
else
{
insert(2*root+2,i,v);
}
}
//查询
void chaxun(int root,int s,int e)
{
if(tree[root].minV>=minV&&tree[root].maxV<=maxV)
{
return ;
}
if(tree[root].L==s&&tree[root].R==e)
{
minV=min(minV,tree[root].minV);
maxV=max(maxV,tree[root].maxV