poj 3321 Apple Tree 线段树

题目大意

  一个有n个节点的树,树的每个节点可能有一个苹果或没有,有两种操作:

  C x 将节点x的权值改变,即如果有一个苹果删掉,否则增加一个苹果。

  Q x 询问以节点x为根的子树中有多少个苹果。

  数据范围:1 <= n <= 100000, 询问个数m <= 100000

 

分析

  对于棵树进行dfs遍历,并记录每一个点的dfs序号(st[i]),在一个节点的所有儿子都被遍历过后,记录当前en[i]为当前最大dfs序号的节点的dfs序号(en[i])。

  将问题转化为了区间操作

  C x 将某一点的权值改变

  Q x 询问区间[st[x],en[x]]的和

  树状数组和线段树可以轻松实现这些操作。

 

代码

type
  pnode=^tnode;
  tnode=record
    lc,rc:pnode;
    c:longint;
end;

var
  t:pnode;
  i,j,k:longint;
  x,y:longint;
  n,m:longint;
  co:longint;
  s:char;
  a:array[0..110000,0..1000] of longint;
  b:array[1..110000,1..3] of longint;

procedure make(r,l:longint);
var
  i,j,k:longint;
begin
  for i:=1 to a[r,0] do
    if a[r,i]=l then break;
  if a[r,i]=l
    then
      begin
        j:=i;
        a[r,0]:=a[r,0]-1;
        for i:=j to a[r,0] do
          a[r,i]:=a[r,i+1];
      end;
  for i:=1 to a[r,0] do
    make(a[r,i],r);
end;

procedure dfs(r:longint;var nm:longint);
var
  i,j,k:longint;
begin
  b[r][1]:=nm;
  for i:=1 to a[r,0] do
    begin
      nm:=nm+1;
      dfs(a[r,i],nm);
    end;
  b[r][2]:=nm;
end;

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 iif: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
                if c=0
                  then
                    begin
                      c:=1;
                      iif:=1;
                    end
                  else
                    begin
                      c:=0;
                      iif:=-1;
                    end;
                exit;
              end;
          if (l<=x) and (mid>=y)
            then
              begin
                neww(lc);
                insert(lc,l,mid,x,y,iif);
                c:=c+iif;
                exit;
              end;
          if (mid<x) and (r>=y)
            then
              begin
                neww(rc);
                insert(rc,mid+1,r,x,y,iif);
                c:=c+iif;
                exit;
              end;
          neww(lc);
          neww(rc);
          insert(lc,l,mid,x,mid,iif);
          c:=c+iif;
          iif:=0;
          insert(rc,mid+1,r,mid+1,y,iif);
          c:=c+iif;
        end;
    {end;}
end;

procedure insert1(var t:pnode; l,r: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=r
            then
              begin
                c:=1;
                exit;
              end;
          neww(lc);
          neww(rc);
          insert1(lc,l,mid);
          c:=c+lc^.c;
          insert1(rc,mid+1,r);
          c:=c+rc^.c;
        end;
    {end;}
end;

function find(t:pnode;l,r,x,y:longint):longint;
var
  mid:longint;
begin
  if t=nil then exit(0);
  with t^ do
    begin
      mid:=(l+r) div 2;
      if (l=x) and (r=y)
        then
          begin
            find:=c;
            exit;
          end;
      if (l<=x) and (mid>=y)
        then
          begin
            find:=find(lc,l,mid,x,y);
            exit;
          end;
      if (mid<x) and (r>=y)
        then
          begin
            find:=find(rc,mid+1,r,x,y);
            exit;
          end;
      find:=find(lc,l,mid,x,mid)+find(rc,mid+1,r,mid+1,y);
    end;
end;

begin
  readln(m);
  for x:=1 to m-1 do
    begin
      readln(i,j);
      a[i,0]:=a[i,0]+1;
      a[i,a[i,0]]:=j;
      a[j,0]:=a[j,0]+1;
      a[j,a[j,0]]:=i;
    end;
  make(1,0);
  i:=1;
  dfs(1,i);
  readln(n);
  fillchar(t,sizeof(t),0);
  j:=0;
  neww(t);
  insert1(t,1,m);
  for i:=1 to n do
    begin
      readln(s,x);
      j:=0;
      if s='C' then insert(t,1,m,b[x][1],b[x][1],j)
               else writeln(find(t,1,m,b[x][1],b[x][2]));
    end;
end.


posted @ 2016-05-22 20:24  一个响亮的蒟蒻  阅读(83)  评论(0编辑  收藏  举报