线段树练习1

来源:互联网 发布:民国算法 编辑:程序博客网 时间:2024/06/15 23:30

虽然早就听说过线段树,而且内部讲课也讲了很多次,但今天才下定决心学习(有点懒哈~)

    线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶节点。    对于线段树中的每一个非叶子节点(编者注:即单点区间,也可以说最后一层)左儿子表示[l,mid],右儿子表示[mid + 1,r]。因此线段树是平衡二叉树,最后的子节点数目为n,即整个区间的长度。————来自百度百科

题目:> http://codevs.cn/problem/1080/

线段数的修改与查找时间复杂度都是O(logn),空间复杂度为4n - 1,但其中有很多空间是浪费的,用指针的话动态构建线段树就不会浪费空间,空间复杂度为2n -1,本着优化空间的原则,我就直接学的指针线段树。

首先是初始化:
注:指针存的是地址,&表示取地址。

struct zt{    int l,r,sum;    zt *lift,*right;};void build(zt *root,int l,int r){    root->sum = 0;root->l = l;root->r = r;    if(l == r)        return;    int mid = (l + r)>>1;    root->lift = &tree[++cnt];    build(root->lift,l,mid);    root->right = &tree[++cnt];    build(root->right,mid + 1,r);}

由于不同的题有不同的写法,关于这道题(单点更新,区间求和)代码如下:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAXN = 2e5 + 5;int n,m,a,b,cnt = 0;struct zt{    int l,r,sum;    zt *lift,*right;};zt tree[MAXN];void build(zt *root,int l,int r){    root->sum = 0;root->l = l;root->r = r;    if(l == r)        return;    int mid = (l + r)>>1;    root->lift = &tree[++cnt];    build(root->lift,l,mid);    root->right = &tree[++cnt];    build(root->right,mid + 1,r);}void add(zt *root,int i,int v){    if(root->l == i&&root->r == i)    {        root->sum+=v;        return;    }    root->sum += v;    int mid = (root->l + root->r)>>1;    if(i > mid)        add(root->right,i,v);    else        add(root->lift,i,v);}int query(zt *root,int l,int r,int ql,int qr){    if(ql <= l&&r <= qr)        return root->sum;    int mid = (l + r)>>1;    if(ql > mid)        return query(root->right,mid + 1,r,ql,qr);    if(qr <= mid)        return query(root->lift,l,mid,ql,qr);    return (query(root->right,mid + 1,r,ql,qr) + query(root->lift,l,mid,ql,qr));}int main(){    scanf("%d",&n);    build(tree,1,n);    for(int i = 1;i <= n;i ++)    {        scanf("%d",&a);        add(tree,i,a);    }    scanf("%d",&m);    for(int i = 1;i <= m;i ++)    {        scanf("%d",&a);        if(a == 1)        {            scanf("%d %d",&a,&b);            add(tree,a,b);        }        else        {            scanf("%d %d",&a,&b);            printf("%d\n",query(tree,1,n,a,b));        }    }    return 0;}
原创粉丝点击