普通线段树
问题
给定长为 的序列 次操作:
A
,有ins x p
:给A[x]
增加p
。ask l r
:询问的区间和。
分治
暴力显然是 的。我们来考虑分治。
假设我们查询 的区间和。如果我们手上已经有 的区间和,那么我们就把问题剖成了两段: . 这是可以很快得出结果的。
按照上面的思路,假设序列长度为 ,那么我们就把整个序列剖成 ,然后进一步剖成 ,这样剖下去,我们就把整个序列剖成了共 个区间。
这就是线段树。
普通线段树
线段树是拥有分治结构的树。它长成这样(借个图):
除了叶子节点,每个节点都有两个儿子。 的左儿子是 ,右儿子是 .
那么题目中的操作就可以这样来处理:
添加操作:对于 个),给这些区间的和加上
x
,找到所有包含它的区间(共p
。
查询操作则要困难一些。我们用一个递归过程实现它:
#define LE(x) ((x)*2) //用数组保存完全二叉树,x*2为x的左儿子,x*2+1为右儿子 #define RT(x) ((x)*2+1) int L=1,R=1027; //L,R代表查询的区间 int ask(int x,int cl,int cr) //cl,cr代表当前区间,x代表当前节点 { int mid=(cl+cr)/2; if(cl>R || cr<L) return 0; //与这个区间毫不相干 if(L<=cl && cr<=R) return sum[x]; //直接包含了这个区间 return ask(LE(x),cl,mid)+ask(RT(x),mid+1,cr); //上述两种情况都不是,则返回两个儿子的查询结果 }
这样,一棵线段树就写出来啦!
评论
发表评论