一个经典问题
已知一组数,有两种操作:
第一个是修改,将第i个数变成另一个数;
第二个是在查询,求[a,b]区间所有值的总和;
例子:
5 3
1
2
3
4
2
2 3 4
2 4 5
1 2 4
10
当有不大于100000个数和不大于100000个询问怎么办,难道o(n*q)?不,看程序吧!!
程序:
type arr=record
lc:longint;【左孩子】
rc:longint;【右孩子】
end;
var
a:array[1..100000]of longint;
b:array[1..100000*4]of arr;
sum,max:array[1..100000*4]of longint; 【数的结点数小于等于一组数的个数*4】
n,m,i,j,a1,a2,a3:longint;
procedure jian(l,r,k:longint);【建立线段树】
var
mid:longint;
begin
if l=r then begin sum[k]:=a[l];exit; end;
mid:=(l+r) div 2;
b[k*2].lc:=l;b[k*2].rc:=mid;
b[k*2+1].lc:=mid+1;b[k*2+1].rc:=r;
jian(l,mid,k*2);
jian(mid+1,r,k*2+1);
sum[k]:=sum[k*2]+sum[k*2+1];
end;
树的样子:
[1,5]
[1,3] [4,5]
[1,2] [3,3] [4,4] [5,5]
[1,1] [2,2]
[1,5]为一区间,[1,3]为一区间,。。。
function cha(l,r,k:longint):longint;
var
mid:longint;
begin
mid:=(b[k].lc+b[k].rc) div 2;cha:=0;
if (l=b[k].lc)and(r=b[k].rc) then exit(sum[k]);
if (l<=mid)and(r<=mid) then cha:=cha+cha(l,r,k*2);
if (l<=mid)and(r>mid) then cha:=cha+cha(l,mid,k*2)+cha(mid+1,r,k*2+1);
if (l>mid)and(r>mid) then cha:=cha+cha(l,r,k*2+1);
[此区间要么都在左边,要么都在右边,要么一边有一点]
end;
procedure d(wei,p,k:longint);
var
mid:longint;
begin
if (b[k].lc=b[k].rc)and(b[k].lc=wei) then
begin
sum[k]:=p;
max[k]:=p;
exit;
end;
sum[k]:=sum[k*2]+sum[k*2+1];
mid:=(b[k].lc+b[k].rc) div 2;
if wei<=mid then d(wei,p,k*2) else d(wei,p,k*2+1);
end;
begin
readln(n,m);[n个数,m个询问]
for i:=1 to n do readln(a[i]);
b[1].lc:=1;b[1].rc:=n;
jian(1,n,1);
for i:=1 to m do
begin
readln(a1,a2,a3);
if a1=1 then
begin
write(cha(a2,a3,1));
end
else if a1=2 then d(a2,a3,1);
end;
end.
回头写个树状数组的,当然树状数组代码很少,却没有线段树实用,建议线段树,树状数组做备用。