http://blog.youkuaiyun.com/metalseed/article/details/8039326
线段树主要用于范围较大的数的查找
多用于区间的动态查询
如求定区间的最值。
1、线段树的叶节点(的value值)表示给定数组的每个值
2、每个内部节点代表其子树中value的最值
线段树的插入方式主要有两类:
1)单点更新
2)成段更新
具体实现
Struct tree{
Int l,r;
Int sum;
int lz;
}a[MAXN*4]; //通常*4最安全
//k 为每个结点的id
NUMBER1 建树过程
Void Build(int l , int r , int k ){
a[k].l = l;
a[k].r = r;
a[k].lz = 0;
if(l==r){
a[k].sum=value[l];
}else{
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
pushup(k);
}
}
注意:pushup()的作用是向上更新,具体实现因题目而异
例://求区间的和
a[k].sum=a[k<<1].sum+a[k<<1|1].sum;
}
if(a[k].l==a[k].r){
a[k].sum+=c;
}else{
int mid=(a[k].l+a[k].r)>>1;
if(x<=mid) insert(x,c,k<<1);
else insert(x,c,k<<1|1);
pushup(k);
}
}
if(l==a[k].l&&a[k].r==r){
a[k].sum+=(r-l+1)*c;
a[k].lz+=c;
}else{
pushdown(k);
int mid=(a[k].l+a[k].r)>>1;
if(r<=mid) insert(l,r,c,k<<1);
else if(l>mid) insert(l,r,c,k<<1|1);
else insert(l,mid,c,k<<1),insert(mid+1,r,c,k<<1|1);
pushup(k);
}
}
NUMBER3 查询操作
A\ 单点查询
/////输入:待查询的值x,k为区间编号(大多从1开始)
ll query(int x,int k){
if(a[k].l==a[k].r){
return a[k].sum;
}else{
pushdown(k);
int mid=(a[k].l+a[k].r)>>1;
if(x<=mid) return query(x,k<<1);
else return query(x,k<<1|1);
}
}
注意:pushdown()的作用,当访问到某区间的lz值不为0,则继续向下更新,并把lz标记一并向下
void pushdown(int k){
if(a[k].lz){
a[k<<1].sum+=(a[k<<1].r-a[k<<1].l+1)*a[k].lz; //更新左、右子树的值
a[k<<1|1].sum+=(a[k<<1|1].r-a[k<<1|1].l+1)*a[k].lz;
a[k<<1].lz+=a[k].lz; //将lz标记推到左、右子树位置,自身的lz值消除
a[k<<1|1].lz+=a[k].lz;
a[k].lz=0;
}
}
ll query(int l,int r,int k){
if(l<=a[k].l&&a[k].r<=r){ //找到的条件是区间完全重合
return a[k].sum;
}else{
pushdown(k);
int mid=(a[k].l+a[k].r)>>1;
if(r<=mid) return query(l,r,k<<1);
else if(l>mid) return query(l,r,k<<1|1);
else return query(l,mid,k<<1)+query(mid+1,r,k<<1|1);
}
}