其实线段树就是以空间来换时间的一种算法
还是以题目来解释。
题目大致内容是给你一个数列有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 ",ask(1,b,c)); } return 0; }
初次写博客,如果有什么地方做的不到位,请在评论区点出,谢谢!