其实这两题都是基础的线段树,但对于我这个线段树的初学者来说,总结一下还是很有用的;
poj3468显然是线段树区间求和,区间更改的问题,而poj2528是对区间染色,问有多少种颜色的问题;
线段树的建立和求和附代码,还是比较简单的;
这里想说的是区间修改,用到了了lazy思想:打标记;
拿poj2528举例,比如对区间[l,r]染色,我们只要在线段树中,被[l,r]覆盖的最大子区间[p,q]上标记被染成了什么颜色即可,不需要再往下遍历[p,q]的左右孩子;当下次修改影响到了区间[p,q]时(区间有交集),说明[p,q]一定不会全都维持原来的颜色。我们将标记向下传递给左右孩子(同时自身标记清除),不断传递下去,直至某个区间完全被要修改区间覆盖,,再给这个区间打上新的标记。这样可保证时间复杂度为O(logn);
总之lazy思想的精髓就是,能不往下访问就不访问,要更改的时候再将子节点更改,从而减少时间复杂度;
1 var lazy,tree:array[0..400000] of int64; 2 l,n,m,j,x,a,b,i:longint; 3 ans:int64; 4 c:char; 5 procedure pushdown(l,r,i:longint); 6 var m:longint; 7 begin 8 m:=(l+r) div 2; 9 if lazy[i]=0 then exit; 10 lazy[i*2]:=lazy[i*2]+lazy[i]; 11 lazy[i*2+1]:=lazy[i*2+1]+lazy[i]; 12 tree[i*2]:=tree[i*2]+lazy[i]*(m-l+1); 13 tree[i*2+1]:=tree[i*2+1]+lazy[i]*(r-m); 14 lazy[i]:=0; 15 end; 16 17 procedure build(i,l,r:longint); 18 var m:longint; 19 begin 20 if l=r then read(tree[i]) 21 else begin 22 m:=(l+r) div 2; 23 build(i*2,l,m); 24 build(2*i+1,m+1,r); 25 tree[i]:=tree[2*i]+tree[2*i+1]; 26 end; 27 end; 28 29 function find(i,l,r,l1,r1:longint):int64; 30 var m:longint; 31 t:int64; 32 begin 33 if (l>=l1) and (r<=r1) then exit(tree[i]) 34 else begin 35 pushdown(l,r,i); 36 m:=(l+r) div 2; 37 t:=0; 38 if l1<=m then t:=t+find(2*i,l,m,l1,r1); 39 if r1>m then t:=t+find(2*i+1,m+1,r,l1,r1); 40 exit(t); 41 end; 42 end; 43 44 procedure work(i,l,r,l1,r1,x:longint); 45 var m:longint; 46 begin 47 if (l1<=l) and (r<=r1) then 48 begin 49 lazy[i]:=lazy[i]+x; 50 tree[i]:=tree[i]+(r-l+1)*x; 51 end 52 else begin 53 pushdown(l,r,i); 54 m:=(l+r) div 2; 55 if (l1<=m) then work(i*2,l,m,l1,r1,x); 56 if (r1>m) then work(i*2+1,m+1,r,l1,r1,x); 57 tree[i]:=tree[i*2]+tree[i*2+1]; 58 end; 59 end; 60 61 62 begin 63 readln(n,m); 64 build(1,1,n); 65 readln; 66 fillchar(lazy,sizeof(lazy),0); 67 for i:=1 to m do 68 begin 69 read(c); 70 if c='Q' then 71 begin 72 read(a,b); 73 ans:=find(1,1,n,a,b); 74 writeln(ans); 75 end 76 else if c='C' then 77 begin 78 read(a,b,j); 79 work(1,1,n,a,b,j); 80 end; 81 readln; 82 end; 83 end.
而poj2528还要复杂一点,简单的建立线段树会爆空间,这需要我们把出现的区间离散化,减小空间复杂度。
1 var tree:array[0..80000] of integer; 2 x,y:array[0..10010] of longint; 3 a:array[0..20010] of longint; //表示离散化乎的标号对应的区间 4 f:array[0..10000000] of boolean; 5 ff:array[0..10010] of boolean; 6 i,j,k,n,t,s:longint; 7 procedure sort(l,r: longint); 8 var i,j,x,y: longint; 9 begin 10 i:=l; 11 j:=r; 12 x:=a[(l+r) div 2]; 13 repeat 14 while a[i]<x do inc(i); 15 while x<a[j] do dec(j); 16 if not(i>j) then 17 begin 18 y:=a[i]; 19 a[i]:=a[j]; 20 a[j]:=y; 21 inc(i); 22 j:=j-1; 23 end; 24 until i>j; 25 if l<j then sort(l,j); 26 if i<r then sort(i,r); 27 end; 28 procedure putdown(i,p,q:longint); //传递标记 29 begin 30 if p<>q then 31 begin 32 tree[i*2]:=tree[i]; 33 tree[i*2+1]:=tree[i]; 34 tree[i]:=0; 35 end; 36 end; 37 procedure build(i,p,q,l,r,x:longint); 38 var m:longint; 39 begin 40 if (a[p]>=l) and (r>=a[q]) then tree[i]:=x 41 else begin 42 if tree[i]<>0 then putdown(i,p,q); 43 m:=(p+q) div 2; 44 if l<=a[m] then 45 begin 46 build(i*2,p,m,l,r,x); 47 end; 48 if r>a[m] then 49 begin 50 build(i*2+1,m+1,q,l,r,x); 51 end; 52 end; 53 end; 54 procedure dfs(i,p,q:longint); //统计多少可见海报 55 var m:longint; 56 begin 57 if (tree[i]>0) and not ff[tree[i]] then 58 begin 59 s:=s+1; 60 ff[tree[i]]:=true; 61 end 62 else if (tree[i]=0) and (p<>q) then 63 begin 64 m:=(p+q) div 2; 65 dfs(i*2,p,m); 66 dfs(i*2+1,m+1,q); 67 end; 68 end; 69 begin 70 readln(t); 71 for i:=1 to t do 72 begin 73 k:=0; 74 fillchar(f,sizeof(f),false); 75 readln(n); 76 for j:=1 to n do 77 begin 78 readln(x[j],y[j]); 79 if not f[x[j]] then //离散化 80 begin 81 k:=k+1; 82 a[k]:=x[j]; 83 f[x[j]]:=true; 84 end; 85 if not f[y[j]] then 86 begin 87 k:=k+1; 88 a[k]:=y[j]; 89 f[y[j]]:=true; 90 end; 91 end; 92 sort(1,k); 93 fillchar(tree,sizeof(tree),0); 94 for j:=1 to n do 95 build(1,1,k,x[j],y[j],j); 96 s:=0; 97 fillchar(ff,sizeof(ff),false); 98 dfs(1,1,k); 99 writeln(s); 100 end; 101 end.