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.