线段树 例一

题目大意

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

 

分析

  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.


 

posted @ 2016-05-14 07:53  一个响亮的蒟蒻  阅读(95)  评论(0编辑  收藏  举报