标签:
对一列数,对每次询问输出对应区间的和,每次修改只修改一个数的值。。。
定义:
struct tree { int l,r;//记录代表的区间 int sum;//代表区间的和 }
由于线段树还是相对比较平衡的,所以可以使用数组t来存储这棵树,
对与某个节点i,t[i*2]就是左子树,t[i*2+1]就是右子树
建树:线段树的思想是每个节点记录区间的信息,某点区间1~n,则1~n/2为其左子树,n/2+1~n为其右子树,每次建立子树方法相同,可以递归建树。。。
至于询问,如果询问区间并不是树上某个确切的节点,就拆分开落到其子树上,追究到底还是递归。。
加和,现在是对点加和还是比较容易的,回溯时将每个节点的sum值更新即可。。。
tree数组开的大小一般是数据数组a大小的4倍
一开始数据读入a数组中,需要的话请自行更改成其他名字。
buildtree(id,l,r) 初次调用id一般是头结点0,l与r是构造的范围,初次调用为1~n或者0~n-1,注意buildtree时要求a中有值,如果建立一个空树,需要把a清零,或者把函数中a[i]出现的地方改为0
update(id,s,w) 初次调用id一般是头结点0,s为需要修改的位置的下标,w为要修改成的值
sum(id,l,r) 初次调用id一般是头结点0,求下标l到r的和的值。
线段树还可以求最大最小值,把求和改成max()或者min()即可。
struct tree { int l,r; int s; }t[400001]; int a[100001]; int p,b,l,r; int calc(int x,int y)//加和运算,如果求最大最小值,更改这里就可以了。 { return x+y; } void buildtree(int id,int l,int r,int *a) { if (l==r) { t[id].l=l; t[id].r=r; t[id].s=a[l]; } else { int mid=(l+r)/2; buildtree(id*2,l,mid,a); buildtree(id*2+1,mid+1,r,a); t[id].l=l; t[id].r=r; t[id].s=calc(t[id*2].s,t[id*2+1].s); } } void update(int id,int s,int w)//s点加上w,可以根据需要改成赋值号 { if (t[id].l==t[id].r) { t[id].s+=w; } else { int mid=(t[id].l+t[id].r)/2; if (s<=mid) update(id*2,s,w); else update(id*2+1,s,w); t[id].s=calc(t[id*2].s,t[id*2+1].s); } } int sum(int id,int l,int r) { if ((t[id].l==l)&&(t[id].r==r)) { return t[id].s; } else { int mid=(t[id].l+t[id].r)/2; if (r<=mid) return sum(id*2,l,r); if (mid<l) return sum(id*2+1,l,r); return calc(sum(id*2,l,mid),sum(id*2+1,mid+1,r)); } }
标签:
原文地址:http://www.cnblogs.com/zhyfzy/p/4293988.html