关于线段树

其实线段树就是以空间来换时间的一种算法

还是以题目来解释。

题目大致内容是给你一个数列有n个数,然后有m个命令,1是让某个点增加一个值,0是询问某个区间的和。

对于这道题,我们一开始可能是想到用循环,但想想,如果数据大了呢,时间就肯定会爆。

所以我们用效率更高的算法,也就是线段数,它的复杂度是log级别的。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct node
{
    int l,r;
    int v;
}p[410000];//最好是题目数据的4倍
int n,m,a[410000];
void build(int id,int l,int r)//建树,id是节点的编号
{
    p[id].l=l;
    p[id].r=r;
    if (l==r)
    {
        p[id].v=a[l];
    }
    else {
        int mid=(l+r)/2;
        build(id*2,l,mid);//递归建树(左儿子)
        build(id*2+1,mid+1,r);//(右儿子)
        p[id].v=p[id*2].v+p[id*2+1].v;
    }
    
}
void update(int id,int pos,int val)
//更新,这里是单点更新,后面会介绍更加快的区间更新
{
        if (p[id].l==p[id].r)
        {
            p[id].v+=val;
        }
        else 
        {
            int mid=(p[id].l+p[id].r)/2;
            if (pos<=mid) 
            update(id*2,pos,val);//同样,递归更新
            else 
            update(id*2+1,pos,val);
            p[id].v=p[id*2].v+p[id*2+1].v;
        }
}
int ask(int id,int l,int r)//询问
{
    if (p[id].l==l&&p[id].r==r)
    return p[id].v;
    else 
    {
        int mid=(p[id].r+p[id].l)/2;
        if (r<=mid) return ask(id*2,l,r);
        else if (l>mid) return ask(id*2+1,l,r);
        else
            return ask(id*2,l,mid)+ask(id*2+1,mid+1,r);
    }
}
int main()
{
    cin>>n;
    for (int i=1;i<=n;i++)
    cin>>a[i];
    build(1,1,n);
    cin>>m;
    for (int i=1;i<=m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        if (a==1) 
        update(1,b,c);
        else printf("%d\n",ask(1,b,c));
    }
    return 0;
}

初次写博客,如果有什么地方做的不到位,请在评论区点出,谢谢!

posted @ 2017-11-18 11:53  雪国大白菜  阅读(129)  评论(0编辑  收藏  举报