线段树是一颗完美二叉树(perfect Binary Tree),所有的叶子深度都相同并且每个节点要么是叶子要么是有2个儿子的树,树上的每个的节点都是维护一个区间。根维护的是整个区间的最小值,每个节点维护的是父亲区间二等分后的其中一个子区间中的最小值。
线段树主要有2种操作:在给定数列a0,a1,a2,....an-1的情况下,
1. 给定s和t,求as,as+1,.....at的最小值 2. 给定i和x, 把ai的值改成x
#define N 1<<16
int n,dat[2*N];
int query(int s,int t,int k,int l,int r)//求(s,t)的最小值,k是节点的编号,l,r对应的是节点k代表的区间[l,r)
{
int vl,vr;
if(r<=s||t<=l)//如果[a,b)与[l,r)不相交,返回一个大值
return INF;
if(s<=l&&t<=b)//如果[a,b)被[l,r)完全包含,则返回当前节点的值
return dat[k];
else//否则返回2个儿子中值的较小值
{
vl=query(s,t,k*2+1,l,(l+r)/2);
vr=query(s,t,k*2+2,l,(l+r)/2);
return vl>vr?vr:vl;
}
}
void update(int k,int x)//把ak的值变成x
{
k+=n-1;//改变第i个节点的值,ai在数组的存储位置是k+n-1 n是叶节点的数量
dat[k]=x;
while(k>0)
{
k=(k-1)/2;//叶节点的值改变了,其父亲节点的值,也应该相应的变化
dat[k]=min(dat[k*2+1],dat[k*2+2]);
}
}