线段树 例一
题目大意
桌子上零散地放着若干个盒子,桌子的后方是一堵墙。如右图所示。现在从桌子的前射来一束平行光, 把盒子的影子投射到了墙上。问影子的总宽度是多少?
分析
1.就是x轴上有若干条线段,求线段覆盖的总长度。
2.给线段树每个节点增加一个域cover。cover=1表示该结点所对应的区间被完全覆盖,cover=0表示该结点所对应的区间未被完全覆盖。最后统计被完全覆盖的节点的长度。
3.线段树可以用数组静态储存:F[r]的左右儿子分别为f[r*2] f[r*2+1]。但是这样写的代码虽然比较简单,但是会浪费很多的空间,因为不是每一个节点会被放置。
type tnode=record l,r:longint; c:longint; end; var t:array[1..1000000] of tnode; i,j,k:longint; x,y:longint; n,m:longint; procedure insert(root,x,y:longint); var i,j,k:longint; mid:longint; begin with t[root] do begin if c=0 then begin mid:=(l+r) div 2; if (l=x) and (r=y) then begin c:=1; exit; end; if (l<=x) and (mid>=y) then begin insert(root*2,x,y); exit; end; if (mid<=x) and (r>=y) then begin insert(root*2+1,x,y); exit; end; insert(root*2,x,mid); insert(root*2+1,mid,y); end; end; end; function find(root:longint):longint; var mid:longint; begin with t[root] do begin if c=1 then exit(r-l); if r-l=1 then exit(0) else exit(find(root*2)+find(root*2+1)); end; end; procedure make(root:longint); var mid:longint; begin with t[root] do begin if r-l>1 then begin mid:=(l+r) div 2; t[root*2].l:=l; t[root*2].r:=mid; t[root*2+1].l:=mid; t[root*2+1].r:=r; make(root*2); make(root*2+1); end; end; end; begin readln(m); fillchar(t,sizeof(t),0); t[1].l:=1; t[1].r:=m; make(1); readln(n); for i:=1 to n do begin readln(x,y); insert(1,x,y); end; write(find(1)); end.
4.线段树还可以用链表动态储存:每当要递归到下一层的时候,如果这个子树还没有建立,就新建这个子树。这样理论上会省空间,但是代码比较复杂。
type pnode=^tnode; tnode=record lc,rc:pnode; c:longint; end; var t:pnode; i,j,k:longint; x,y:longint; n,m:longint; 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:longint); var i,j,k:longint; mid:longint; begin with t^ do begin if c=0 then begin mid:=(l+r) div 2; if (l=x) and (r=y) then begin c:=1; exit; end; if (l<=x) and (mid>=y) then begin neww(lc); insert(lc,l,mid,x,y); exit; end; if (mid<=x) and (r>=y) then begin neww(rc); insert(rc,mid,r,x,y); exit; end; neww(lc); neww(rc); insert(lc,l,mid,x,mid); insert(rc,mid,r,mid,y); end; end; end; function find(t:pnode;l,r:longint):longint; var mid:longint; begin if t=nil then exit(0); with t^ do begin mid:=(l+r) div 2; if c=1 then exit(r-l); exit(find(lc,l,mid)+find(rc,mid,r)); end; end; begin readln(m); readln(n); fillchar(t,sizeof(t),0); neww(t); for i:=1 to n do begin readln(x,y); insert(t,1,m,x,y); end; write(find(t,1,m)); end.