线段树 例四
题目大意
x轴上有若干条不同线段,问某个单位区间[x,y]上重叠了多少条线段?
分析
加一个域count,当线段完全覆盖区间[a,b]时,把[a,b]的count域加一。
思考线段树的构造方法:当某线段能够完整覆盖某个结点所对应的区间时,则不再二分。因此要统计某个单位区间上重叠的线段总数,必须把从叶结点到根结点路径上所有结点的count域累加。
所以统计算法时,要用和插入算法一样的二分法:使得可以把所有的要加的区间找出来。
代码
type pnode=^tnode; tnode=record lc,rc:pnode; c:longint; end; var t:pnode; i,j,k:longint; x,y:longint; n,m:longint; ans: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:=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; procedure find(t:pnode;l,r:longint;x,y:longint); var mid:longint; begin if t=nil then exit(); {with t^ do begin mid:=(l+r) div 2; if c=1 then exit(r-l); exit(find(lc,l,mid,x,y)+find(rc,mid,r,x,y)); end; } with t^ do begin {if c=0 then begin } ans:=ans+c; mid:=(l+r) div 2; if (l<=x) and (mid>=y) then begin find(lc,l,mid,x,y); exit; end; if (mid<=x) and (r>=y) then begin find(rc,mid,r,x,y); exit; end; find(lc,l,mid,x,mid); find(rc,mid,r,mid,y); { end; } 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; readln(x,y); find(t,1,m,x,y); write(ans); end.