周中训练笔记(四)

来源:互联网 发布:药智网数据库vip 编辑:程序博客网 时间:2024/06/06 03:59

线段树总结:

线段树存储的是区间的信息然后在可以进行区间的各种操作。

对于节点a[n]它的左儿子为a[2*n]右儿子为a[2*n+1]。

假如这个节点所表示的区间为[1,5]那么它左儿子表示的区间为[1,3],右儿子表示的区间为[4,5],公式为mid=(l+r)/2,左儿子表示的区间为(l,mid),右儿子表示的区间为(mid+1,r)。

线段树的建立:void build(int id,int l,int r) {
tree[id].left=l; tree[id].right=r;
if (l==r)
{
tree[id].sum=a[l];
tree[id].max=a[l];
}
else
{
int mid=(l+r)/2;
build(id*2,l,mid);
build(id*2+1,mid+1,r);
tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
tree[id].max=max(tree[id*2].max,tree[id*2+1].max;
}
}

我的理解:1.调用build(1,1,n)既可以将a[1]~a[n]的数就存到了二叉树中,通过递归调用函数为线段树进行便利。

   2.当l==r时即进行tree[id].sum=a[l],tree[id].max=a[l]操作,当l==r时此时的区间只有一个值所以直接令其等于a[l]即可。

          3.当l!=r时调用tree[id].sum=tree[id*2].sum+tree[id*2+1].sum,tree[id].max=max(tree[id*2].max,tree[id*2+1].max既可以求出值,依次求最后最上面的即是所要的max和sum。

线段树的更新:oid update(int id,int pos,int val) {
if (tree[id].left==tree[id].right)
{
tree[id].sum=tree[id].max=val;
}
else
{
int mid=(tree[id].left+tree[id].right)/2;
if (pos<=mid) update(id*2,pos,val);
else update(id*2+1,pos,val);
tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
tree[id].max=max(tree[id*2].max,tree[id*2+1].max)
}
}

我的理解:通过递归函数层层深入,知道搜索到更新的那点的位置时给那一点重新赋值,然后包含这一个点的区间的值都得更新,if (pos<=mid)通过这一个判断就能保证数值更新的正确。

线段树的最大值计算:void query(int id,int l,int r){
if (tree[id].left==l&&tree[id].right==r)
return tree[id].sum; 
else
{
int mid=(tree[id].left+tree[id].right)/2;
if (r<=mid) return query(id*2,l,r);
else if (l>mid) return query(id*2+1,l,r)
else
  return query(id*2,l,mid)+query(id*2+1,mid+1,r);
}
}

我的理解:同样通过递归函数从底层返回上来求和,else里面的判断就可以确定这个节点是两个儿子的和还是其中一个的值,然后最后返回到第一次调用函数的时候tree[1].left==l&&tree[1].right==r即输出结果就行。

原创粉丝点击