线段树 例二
题目大意
桌子上零散地放着若干个不同颜色的盒子,桌子的后方是一堵墙。如右图所示。问从桌子前方可以看到多少个盒子?假设人站得足够远。
分析
可以这样来看这道题:x轴上有若干条不同线段,将它们依次染上不同的颜色,问最后能看到多少种不同的颜色?(后染的颜色会覆盖原先的颜色)
我们可以这样规定:x轴初始是颜色0,第一条线段染颜色1,第二条线段染颜色2,以此类推。
原先构造线段树的方法不再适用,但是我们可以通过修改线段树的cover域的定义,使得这道题也能用线段树来解。定义cover如下:cover=-1表示该区间由多种颜色组成。cover>=0表示该区间只有一种单一的颜色cover。
使用一个数组Flag,初始化为0。遍历线段树,对于每种颜色c对Flag[c]赋值1。最后统计Flag中1的个数即可。(注意颜色0应该排除在外,可以在最后减1)
代码
type pnode=^tnode; tnode=record lc,rc:pnode; c:longint; end; var t:pnode; i,j,k:longint; x,y:longint; n,m:longint; f:array[0..100000] of 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,ce:longint); var i,j,k:longint; mid:longint; begin with t^ do begin if c<>ce then begin mid:=(l+r) div 2; if (l=x) and (r=y) then begin c:=ce; exit; end; if c<>-1 then begin neww(lc); neww(rc); lc^.c:=t^.c; rc^.c:=t^.c; t^.c:=-1; end; if (l<=x) and (mid>=y) then begin neww(lc); insert(lc,l,mid,x,y,ce); exit; end; if (mid<=x) and (r>=y) then begin neww(rc); insert(rc,mid,r,x,y,ce); exit; end; neww(lc); neww(rc); insert(lc,l,mid,x,mid,ce); insert(rc,mid,r,mid,y,ce); end; end; end; procedure find(t:pnode;l,r:longint); var mid:longint; begin if t=nil then exit; with t^ do begin mid:=(l+r) div 2; if c<>-1 then begin f[c]:=1; exit; end; 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,i); end; find(t,1,m); i:=0; for j:=1 to n+10 do if f[j]=1 then i:=i+1; write(i); end.