线段树 例五
题目大意
一行N个方格,开始每个格子里的数都是0。现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和;修改的规则是指定某一个格子x,加上或者减去一个特定的值A。现在要求你能对每个提问作出正确的回答。
分析
方法一:线段树
为线段树每个节点增加一个Count域。表示所对应区间内元素之和。每次修改一个格子,需要修改从叶结点到根结点路径上所有结点的值。
所以统计算法时,要用和插入算法一样的二分法:使得可以把所有的要加的区间找出来。
注意,目中的区间是以元素为端点,因此[a,b]和[b,c]存在重合。具体见代码:
type pnode=^tnode; tnode=record lc,rc:pnode; c:longint; end; var t:pnode; i,j,k:longint; x,y:longint; n,m:longint; co:longint; s:char; procedure neww(var t:pnode); begin if t=nil then begin new(t); t^.c:=0; t^.lc:=nil; t^.rc:=nil; end; end; procedure insert(var t:pnode; l,r,x,y,co:longint); var i,j,k:longint; mid:longint; begin with t^ do begin {if c=0 then begin } c:=c+co; mid:=(l+r) div 2; if (l=x) and (r=y) then exit; if (l<=x) and (mid>=y) then begin neww(lc); insert(lc,l,mid,x,y,co); exit; end; if (mid<x) and (r>=y) then begin neww(rc); insert(rc,mid+1,r,x,y,co); exit; end; neww(lc); neww(rc); insert(lc,l,mid,x,mid,co); insert(rc,mid+1,r,mid+1,y,co); end; {end;} end; function find(t:pnode;l,r,x,y:longint):longint; var mid:longint; begin if t=nil then exit(0); with t^ do begin mid:=(l+r) div 2; if (l=x) and (r=y) then begin find:=c; exit; end; if (l<=x) and (mid>=y) then begin find:=find(lc,l,mid,x,y); exit; end; if (mid<x) and (r>=y) then begin find:=find(rc,mid+1,r,x,y); exit; end; find:=find(lc,l,mid,x,mid)+find(rc,mid+1,r,mid+1,y); end; end; begin readln(m); readln(n); fillchar(t,sizeof(t),0); neww(t); for i:=1 to n do begin readln(s,x,co); if s='M' then insert(t,1,m,x,x,co) else write(find(t,1,m,x,co)); end; end.
方法二:树状数组
var n,m:longint; a,b:array[0..40000] of longint; i,j,k:longint; x,y:longint; s:char; procedure bian(p,c:longint); begin while p<=m do begin b[p]:=b[p]+c; p:=p+(p and (p xor (p-1))); end; end; function tong(p:longint):longint; begin tong:=0; while p>0 do begin tong:=tong+b[p]; p:=p-(p and (p xor (p-1))); end; end; begin readln(m); readln(n); j:=0; for i:=1 to n do begin readln(s,x,y); if s='M' then bian(x,y) else writeln(tong(y)-tong(x-1)); end; end.