BZOJ 1036: [ZJOI2008]树的统计Count(树链剖分)

                                                                           树的统计Count
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
Input
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
4
1
2
2
10
6
5
6
5
16

分析:

树链剖分模板题,参照hzwer的程序写的。

代码:

program bzoj_1036;
type
  point=record
     l,r,sum,max:longint;
  end;
  message=record
     t,next:longint;
  end;
var
  e:array[0..60000]of message;
  w:array[0..120000]of point;
  fa:array[0..30000,0..14]of longint;
  head,v,size,belong,deep,post:array[0..30000]of longint;
  vis:array[0..30000]of boolean;
  n,m,sz:longint;
procedure insert(x,y:longint);
begin
  inc(m); e[m].t:=x; e[m].next:=head[y]; head[y]:=m;
  inc(m); e[m].t:=y; e[m].next:=head[x]; head[x]:=m;
end;
function max(x,y:longint):longint;
begin
  if x>y then max:=x else max:=y;
end;
procedure int;
var i,x,y:longint;
begin
  readln(n);  sz:=0; m:=0;
  for i:=1 to n-1 do
   begin readln(x,y); insert(x,y);  end;
  for i:=1 to n do read(v[i]);
  fillchar(vis,sizeof(vis),false);
end;
procedure dfs1(x:longint);
var i:longint;
begin
  size[x]:=1; vis[x]:=true;
  for i:=1 to 14 do
   begin
     if deep[x]<(1<<i) then break;
     fa[x,i]:=fa[fa[x,i-1],i-1];
   end;
  i:=head[x];
  while i>0 do
  begin
    if vis[e[i].t] then begin i:=e[i].next; continue; end;
    deep[e[i].t]:=deep[x]+1;
    fa[e[i].t][0]:=x;
    dfs1(e[i].t);
    inc(size[x],size[e[i].t]);
    i:=e[i].next;
  end;
end;
procedure dfs2(x,chain:longint);
var i,k:longint;
begin
  k:=0; inc(sz);post[x]:=sz;belong[x]:=chain;
  i:=head[x];
  while i>0 do
   begin
     if (deep[e[i].t]>deep[x])and(size[e[i].t]>size[k]) then  k:=e[i].t;
     i:=e[i].next;
   end;
  if k=0 then exit;
  dfs2(k,chain);
  i:=head[x];
  while i>0 do
   begin
     if (deep[e[i].t]>deep[x])and(k<>e[i].t) then dfs2(e[i].t,e[i].t);
     i:=e[i].next;
   end;
end;
function lca(x,y:longint):longint;
var i,t,u:longint;
begin
  if  deep[x]<deep[y] then begin u:=x; x:=y; y:=u; end;
  t:=deep[x]-deep[y];
  for i:=0 to 14 do
    if (t and (1<<i))>0 then x:=fa[x,i];
  for i:=14 downto 0 do
    if (fa[x,i]<>fa[y,i]) then begin x:=fa[x,i];y:=fa[y,i]; end;
  if x=y then exit(x) else exit(fa[x,0]);
end;
procedure build(p,l,r:longint);
var mid:longint;
begin
  w[p].l:=l; w[p].r:=r; w[p].max:=-maxlongint; w[p].sum:=0;
  if l=r then exit; mid:=(l+r) div 2;
  build(p*2,l,mid); build(p*2+1,mid+1,r);
end;
procedure change(p,x,num:longint);
var mid:longint;
begin
  if w[p].l=w[p].r then begin w[p].sum:=num; w[p].max:=num; end
  else
    begin
      mid:=(w[p].l+w[p].r) div 2;
      if x<=mid then change(p*2,x,num) else
        if x>mid then change(p*2+1,x,num);
      w[p].sum:=w[p*2].sum+w[p*2+1].sum;
      w[p].max:=max(w[p*2].max,w[p*2+1].max);
    end;
end;
function querysum(p,l,r:longint):longint;
var mid,ans:longint;
begin
  if (l<=w[p].l)and(w[p].r<=r) then exit(w[p].sum)
   else
    begin
      mid:=(w[p].l+w[p].r) div 2; ans:=0;
      if l<=mid then inc(ans,querysum(p*2,l,r));
      if r>mid then inc(ans,querysum(p*2+1,l,r));
      exit(ans);
    end;
end;
function querymax(p,l,r:longint):longint;
var mid,ans:longint;
begin
  if (l<=w[p].l)and(w[p].r<=r) then exit(w[p].max)
  else
   begin
     mid:=(w[p].l+w[p].r) div 2; ans:=-maxlongint;
     if l<=mid  then ans:=max(ans,querymax(p*2,l,r));
     if r>mid then ans:=max(ans,querymax(p*2+1,l,r));
     exit(ans);
   end;
end;
function solvesum(x,f:longint):longint;
var sum:longint;
begin
  sum:=0;
  while (belong[x]<>belong[f]) do
  begin
    inc(sum,querysum(1,post[belong[x]],post[x])); x:=fa[belong[x],0];
  end;
  inc(sum,querysum(1,post[f],post[x])); exit(sum);
end;
function solvemax(x,f:longint):longint;
var ans:longint;
begin
  ans:=-maxlongint;
  while (belong[x]<>belong[f]) do
  begin
    ans:=max(ans,querymax(1,post[belong[x]],post[x]));x:=fa[belong[x],0];
  end;
  ans:=max(ans,querymax(1,post[f],post[x])); exit(ans);
end;
procedure solve;
var i,x,y,q,t,l:longint; s:string;  ch,gy:char;
begin
  build(1,1,n);
  for i:=1 to n do
   change(1,post[i],v[i]);
  readln(q);
  for i:=1 to q do
   begin
     readln(s); ch:=s[1]; gy:=s[2];
     l:=pos(' ',s); delete(s,1,l);
     l:=pos(' ',s); val(copy(s,1,l-1),x);
     val(copy(s,l+1,length(s)-l),y);
     if ch='C' then begin v[x]:=y; change(1,post[x],y); end
     else
     begin
       t:=lca(x,y); if gy='M' then writeln(max(solvemax(x,t),solvemax(y,t)))
       else writeln(solvesum(x,t)+solvesum(y,t)-v[t]);
     end;
   end;
end;
begin
  assign(input,'bzoj_1036.in');reset(input);
  assign(output,'bzoj_1036.out');rewrite(output);
  int;
  dfs1(1); dfs2(1,1); solve;
  close(input); close(output);
end.
View Code

 

posted @ 2016-04-14 18:47  QTY_YTQ  阅读(206)  评论(0编辑  收藏  举报