树链剖分(+线段树)(codevs4633)
Posted z1j1n1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树链剖分(+线段树)(codevs4633)相关的知识,希望对你有一定的参考价值。
type node=^link; link=record des:longint; next:node; end; type seg=record z,y,lc,rc,toadd,sum:longint; end; var n,tot,i,t1,t2,q,a,b,c:longint; p:node; son,siz,dep,fa,num,top:array[1..100000] of longint; tr:array[0..250000] of seg; nd:array[1..100000] of node; function max(a,b:longint):longint; begin if a>b then exit(a) else exit(b); end; function min(a,b:longint):longint; begin if a>b then exit(b) else exit(a); end; procedure dfs1(po:longint); var p:node; begin siz[po]:=1;son[po]:=0; p:=nd[po]; while p<>nil do begin if dep[p^.des]=0 then begin dep[p^.des]:=dep[po]+1; fa[p^.des]:=po; dfs1(p^.des); if siz[p^.des]>siz[son[po]] then son[po]:=p^.des; siz[po]:=siz[po]+siz[p^.des]; end; p:=p^.next; end; end;//寻找非叶子结点中儿子siz最大,记录在son中 procedure dfs2(po,tp:longint); var p:node; begin inc(tot); num[po]:=tot; top[po]:=tp; if son[po]<>0 then dfs2(son[po],tp); p:=nd[po]; while p<>nil do begin if (p^.des<>son[po]) and (p^.des<>fa[po]) then dfs2(p^.des,p^.des); p:=p^.next; end; end;//将重边练成重链,num记录树上的点哈希到线段树上的结果 procedure buildtree(l,r:longint); var t:longint; begin inc(tot); tr[tot].sum:=0;tr[tot].toadd:=0; tr[tot].z:=l;tr[tot].y:=r; t:=tot; if l=r then exit else begin tr[t].lc:=tot+1; buildtree(l,(l+r) div 2); tr[t].rc:=tot+1; buildtree((l+r) div 2+1,r); end; end;//建线段树 procedure add(po,l,r,k:longint); var mid:longint; begin if tr[po].toadd<>0 then begin tr[po].sum:=tr[po].sum+(tr[po].y-tr[po].z+1)*tr[po].toadd; tr[tr[po].lc].toadd:=tr[tr[po].lc].toadd+tr[po].toadd; tr[tr[po].rc].toadd:=tr[tr[po].rc].toadd+tr[po].toadd; tr[po].toadd:=0; end; mid:=(tr[po].z+tr[po].y) div 2; tr[po].sum:=tr[po].sum+(r-l+1)*k; if (l=tr[po].z) and (r=tr[po].y) then begin tr[tr[po].lc].toadd:=tr[tr[po].lc].toadd+k; tr[tr[po].rc].toadd:=tr[tr[po].rc].toadd+k; exit; end else begin if mid>=l then add(tr[po].lc,l,min(mid,r),k); if r>mid then add(tr[po].rc,max(mid+1,l),r,k); end; end;//线段树加 function ans(po,l,r:longint):longint; var mid:longint; begin if tr[po].toadd<>0 then begin tr[po].sum:=tr[po].sum+(tr[po].y-tr[po].z+1)*tr[po].toadd; tr[tr[po].lc].toadd:=tr[tr[po].lc].toadd+tr[po].toadd; tr[tr[po].rc].toadd:=tr[tr[po].rc].toadd+tr[po].toadd; tr[po].toadd:=0; end; mid:=(tr[po].z+tr[po].y) div 2; if (l=tr[po].z) and (r=tr[po].y) then exit(tr[po].sum) else begin ans:=0; if mid>=l then ans:=ans+ans(tr[po].lc,l,min(mid,r)); if r>mid then ans:=ans+ans(tr[po].rc,max(mid+1,l),r); end; end;//线段树求和 procedure plus(b,c:longint); begin while top[b]<>top[c] do begin if dep[top[b]]<dep[top[c]] then begin add(1,num[top[c]],num[c],1); c:=fa[top[c]]; end else begin add(1,num[top[b]],num[b],1); b:=fa[top[b]]; end; end; if num[b]<num[c] then add(1,num[b],num[c],1) else add(1,num[c],num[b],1); end;//通过重链寻找被修改的区间 function query(b,c:longint):longint; begin query:=0; while top[b]<>top[c] do begin if dep[top[b]]<dep[top[c]] then begin query:=query+ans(1,num[top[c]],num[c]); c:=fa[top[c]]; end else begin query:=query+ans(1,num[top[b]],num[b]); b:=fa[top[b]]; end; end; if num[b]<num[c] then query:=query+ans(1,num[b],num[c]) else query:=query+ans(1,num[c],num[b]); end;//通过重链寻找被求和的区间 begin read(n); for i:=1 to n-1 do begin read(t1,t2); new(p); p^.des:=t2;p^.next:=nd[t1];nd[t1]:=p; new(p); p^.des:=t1;p^.next:=nd[t2];nd[t2]:=p; end; dep[1]:=1; dfs1(1); dfs2(1,1); tot:=0; buildtree(1,n); read(q); for i:=1 to q do begin read(a,b,c); if a=1 then plus(b,c); if a=2 then writeln(query(b,c)); end; end.
以上是关于树链剖分(+线段树)(codevs4633)的主要内容,如果未能解决你的问题,请参考以下文章