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.