线段树经典题

  

    桌子上零散地放着若干个盒子,桌子的后方是一堵墙。如右图所示。现在从桌子的前方射来一束平行光,把盒子的影子投射到了墙上。问影子的总宽度是多少?

线段树经典题_第1张图片

分析:使用一个下标范围为[min,max-1]的一维数组,其中数组的第i个元素表示[i,i+1]的区间,将[a,b]内所有对应的数组元素均设为1。最后统计数组中1的个数即可。当下标范围很大时,速度会很慢。这样就需要用线段树(二叉树)来写了。


如果根节点为1—n,那么两个儿子节点分别为1—mid和mid—n(注意:其中1、mid、n是点)。

每个节点都可以记录一些信息。在该题中,加一个cover,记录i—j完全覆盖与否,就可以快速求解,再加上离散化,可以大大节约内存。

 

const

  maxn=2000;

type

 tnode=record

         b,e:integer;  {节点的范围}

         cover:integer;  {完全覆盖为1,不完全覆盖为0}

        end;

var

 tree:array[1..maxn] of tnode;

 n,total:integer;

 

procedure insert(p,a,b:integer);

var

  m:integer;

begin

  if tree[p].cover=0

    then begin

           m:=(tree[p].b+tree[p].e) div 2;  //求mid

            if (tree[p].b=a) and(tree[p].e=b)  //如果插入的范围刚好为tree[b—e],那//么直接赋值为完全覆盖

             then tree[p].cover:=1

             else begin

                     if b<=m

                       then  insert(p*2,a,b)    //如果插入的范围只在左节点,那么直接//枚举左儿子

                       else if a>=m

                               theninsert(p*2+1,a,b) //只有右儿子

                               else begin

                                     insert(p*2,a,m);  //既有左儿子,又有右儿子

                                     insert(p*2+1,m,b);

                                    end;

                   end;

        end;

end;

 

function count(p:integer):integer;//递归求和

begin

  if tree[p].cover=1

    thencount:=tree[p].e-tree[p].b

    else if tree[p].e-tree[p].b=1

          then count:=0

          else count:=count(p*2)+count(p*2+1);

end;

 

procedure create(p:integer);//建树,可以用离散化优化

var

  m:integer;

begin

   if tree[p].e-tree[p].b>1 then

     begin

      m:=(tree[p].e+tree[p].b) div 2;

      tree[p*2].b:=tree[p].b;

      tree[p*2].e:=m;

      tree[p*2+1].b:=m;

      tree[p*2+1].e:=tree[p].e;

       create(p*2);

      create(p*2+1);

     end;

end;

 

procedure main;

var

  i:integer;

 a,b,l:integer;

begin

  readln(l);

 tree[1].b:=1;tree[1].e:=l;

  create(1);

  readln(n);

  for i:=1 to n do

    begin

     read(a,b);

     insert(1,a,b);

    end;

 total:=count(1);

end;

 

begin

  main;

  writeln(total);

end.

 

你可能感兴趣的:(线段树)