线段树 例二

题目大意

  桌子上零散地放着若干个不同颜色的盒子,桌子的后方是一堵墙。如右图所示。问从桌子前方可以看到多少个盒子?假设人站得足够远。

 

分析

  可以这样来看这道题: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.


  

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