[BZOJ1036][ZJOI2008]树的统计Count 解题报告|树链剖分
树链剖分
简单来说就是数据结构在树上的应用。常用的为线段树splay等。(可现在splay还不会敲囧)
重链剖分:
将树上的边分成轻链和重链。
重边为每个节点到它子树最大的儿子的边,其余为轻边。
设(u,v)为轻边,则size(v)<=size(u)/2 (一旦大于了那必然是重边)
也就是一条路径上每增加一条轻边节点个数就会减少一半以上,那么显然根到任意一个节点路径上的轻边条数一定不会超过log(n)(不然节点就没了啊23333)
重链定义为一条极长的连续的且全由重边构成的链。
容易看出重链两两互不相交
而且在一条路径上重链是由一条条轻边隔开的,所以重链的条数也<=log(n)
我们先进行一次dfs可以将每个节点子树的大小记录好
再进行一次dfs可以刷出重边以及构造重链
dfs2过程的意图和实现
显然每个点在且仅在一条重链里,那么对于点信息的维护我们就可以用将这些链首尾相接放到一个大的线段树里面做
按照dfs序将重链插入线段树,具体的实现是给每个点重新赋一个标号,并且记录每个点所在的链的头节点
先遍历一遍子节点找出一个子树最大的儿子,继续拓展下去
对于剩下的儿子以儿子节点为起点重新开始一条重链
对于询问路径上加和\最值等问题,如何将询问的区间转移到线段树上?
首先可以用倍增算法找到两点(x,y)的最近公共祖先t
然后分别对(x,t)和(y,t)两条路径操作
理想状态是x,t在同一条重链中,那样我们就可以直接在线段树上做了
(为啥不在一条重链中就不可以直接做呢。。?)
像上图这种情况,橙色的点是我们要求的区间。
但是显然在处理到第二个点的时候,会优先向右拓展
编号就不是连续的了。只有在一条重链中才能保证编号的连续的。
(这里的编号指的是在dfs2过程中新的编号)
我们为了达到这种理想状态,就要从x节点一点一点向上爬
每次累加x所在重链的头节点到x节点区间内的答案,然后跳过向上的一条轻边,直到最后的x,t在同一条重链中,再统计在这条重链中的答案
由于重链和轻边的条数都不会超过log(n),所以这一步的复杂度也可以粗略估计为O(log(n))
统计答案就是最基础的线段树操作。
另外由于刚开始并不大理解线段树是一个而不是每条重链上一个,所以还去算了一下重链的条数最大值来估计空间。。。
附上非常奇怪的证明
以下所有u节点表示重边起点,v节点表示重边终点,x表示重链条数
以每个非叶子节点为起点都会产生一条重链
每个非叶子的v节点又会在上面基础上减少一条重链的产生
X=非叶子节点数-非叶子节点中的v节点数
非叶子节点中的v节点数=v节点数-叶子节点中的v节点数
V节点数=u节点数=非叶子节点数
非叶子节点中的v节点数=非叶子节点数-叶子节点中的v节点数
X=非叶子节点数-(非叶子节点数-叶子节点中的v节点数)
= 叶子节点中的v节点数
我们只要保证每个叶子节点的父亲都只有一个儿子就可以使每个叶子节点都是v节点
Max(X)=Max(叶子节点中的v节点数)=叶子节点数
BZOJ1036[ZJOI2008]树的统计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本身
多余的分析就不需要了 上面讲树链剖分就是以这道题为例的
感谢黄学长的模板看了一遍就完全理解了 而且写得很漂亮
代码略长,以后可以多写写练练手感
1 program bzoj1036; 2 const maxn=30010;maxm=60010; 3 var n,i,j,x,y,q,cnt,t:longint; 4 ch:char; 5 ter,next:array[-1..maxm]of longint; 6 deep,pos,size,link,belong,v:array[-1..maxn]of longint; 7 fa:array[-1..maxn,-1..15]of longint; 8 tr:array[-1..5*maxn]of record l,r,mx,sum:longint;end; 9 10 function max(a,b:longint):longint; 11 begin 12 if a>b then exit(a) else exit(b); 13 end; 14 15 procedure add(x,y:longint); 16 begin 17 inc(j);ter[j]:=y;next[j]:=link[x];link[x]:=j; 18 inc(j);ter[j]:=x;next[j]:=link[y];link[y]:=j; 19 end; 20 21 procedure dfs1(p:longint); 22 var j:longint; 23 begin 24 size[p]:=1; 25 for i:=1 to 14 do 26 begin 27 if deep[p]<=1 << i then break; 28 fa[p][i]:=fa[fa[p][i-1]][i-1]; 29 end; 30 j:=link[p]; 31 while j<>0 do 32 begin 33 if deep[ter[j]]=0 then 34 begin 35 deep[ter[j]]:=deep[p]+1; 36 fa[ter[j]][0]:=p; 37 dfs1(ter[j]); 38 inc(size[p],size[ter[j]]); 39 end; 40 j:=next[j]; 41 end; 42 end; 43 44 procedure dfs2(p,chain:longint); 45 var k,j:longint; 46 begin 47 inc(cnt);pos[p]:=cnt;belong[p]:=chain; 48 k:=0; 49 j:=link[p]; 50 while j<>0 do 51 begin 52 if deep[ter[j]]>deep[p] then 53 if size[ter[j]]>size[k] then k:=ter[j]; 54 j:=next[j]; 55 end; 56 if k=0 then exit; 57 dfs2(k,chain); 58 j:=link[p]; 59 while j<>0 do 60 begin 61 if deep[ter[j]]>deep[p] then 62 if ter[j]<>k then dfs2(ter[j],ter[j]); 63 j:=next[j]; 64 end; 65 end; 66 67 procedure build(p,l,r:longint); 68 var mid:longint; 69 begin 70 tr[p].l:=l;tr[p].r:=r;tr[p].sum:=0;tr[p].mx:=-maxlongint; 71 if l=r then exit; 72 mid:=(l+r) >> 1; 73 build(p << 1,l,mid); 74 build(p << 1+1,mid+1,r); 75 end; 76 77 procedure insert(p,loc,x:longint); 78 var mid:longint; 79 begin 80 if (tr[p].l=loc)and(tr[p].r=loc) then 81 begin 82 tr[p].sum:=x;tr[p].mx:=x; 83 exit; 84 end; 85 mid:=(tr[p].l+tr[p].r) >> 1; 86 if loc<=mid then insert(p << 1,loc,x) else insert(p << 1+1,loc,x); 87 tr[p].sum:=tr[p << 1].sum+tr[p << 1+1].sum; 88 tr[p].mx:=max(tr[p << 1].mx,tr[p << 1+1].mx); 89 end; 90 91 function lca(x,y:longint):longint; 92 var i,tem:longint; 93 begin 94 if deep[x]<deep[y] then 95 begin 96 tem:=x;x:=y;y:=tem; 97 end; 98 if deep[x]<>deep[y] then 99 begin 100 i:=trunc(ln(deep[x]-deep[y])/ln(2)); 101 while deep[x]>deep[y] do 102 begin 103 while (deep[x]-deep[y]>=1 << i) do x:=fa[x][i]; 104 dec(i); 105 end; 106 end; 107 if x=y then exit(x); 108 i:=trunc(ln(n)/ln(2)); 109 while fa[x][0]<>fa[y][0] do 110 begin 111 while fa[x][i]<>fa[y][i] do 112 begin 113 x:=fa[x][i];y:=fa[y][i]; 114 end; 115 dec(i); 116 end; 117 exit(fa[x][0]); 118 end; 119 120 function query_sum(p,l,r:longint):longint; 121 var mid:longint; 122 begin 123 if (tr[p].l=l)and(tr[p].r=r) then exit(tr[p].sum); 124 mid:=(tr[p].l+tr[p].r) >> 1; 125 if r<=mid then exit(query_sum(p << 1,l,r)) else 126 if l>mid then exit(query_sum(p << 1+1,l,r)) else 127 exit(query_sum(p << 1,l,mid)+query_sum(p << 1+1,mid+1,r)); 128 end; 129 130 function query_mx(p,l,r:longint):longint; 131 var mid:longint; 132 begin 133 if (tr[p].l=l)and(tr[p].r=r) then exit(tr[p].mx); 134 mid:=(tr[p].l+tr[p].r) >> 1; 135 if r<=mid then exit(query_mx(p << 1,l,r)) else 136 if l>mid then exit(query_mx(p << 1+1,l,r)) else 137 exit(max(query_mx(p << 1,l,mid),query_mx(p << 1+1,mid+1,r))); 138 end; 139 140 function solve_sum(x,y:longint):longint; 141 var sum:longint; 142 begin 143 sum:=0; 144 while belong[x]<>belong[y] do 145 begin 146 inc(sum,query_sum(1,pos[belong[x]],pos[x])); 147 x:=fa[belong[x]][0]; 148 end; 149 inc(sum,query_sum(1,pos[y],pos[x])); 150 exit(sum); 151 end; 152 153 function solve_mx(x,y:longint):longint; 154 var mx:longint; 155 begin 156 mx:=-maxlongint; 157 while belong[x]<>belong[y] do 158 begin 159 mx:=max(mx,query_mx(1,pos[belong[x]],pos[x])); 160 x:=fa[belong[x]][0]; 161 end; 162 mx:=max(mx,query_mx(1,pos[y],pos[x])); 163 exit(mx); 164 end; 165 166 begin 167 readln(n); 168 for i:=1 to n-1 do 169 begin 170 readln(x,y); 171 add(x,y); 172 end; 173 deep[1]:=1;dfs1(1);cnt:=0;dfs2(1,1); 174 build(1,1,n); 175 for i:=1 to n do 176 begin 177 read(v[i]); 178 insert(1,pos[i],v[i]); 179 end; 180 readln(q); 181 for i:=1 to q do 182 begin 183 read(ch); 184 if ch='C' then 185 begin 186 readln(ch,ch,ch,ch,ch,x,y); 187 v[x]:=y; 188 insert(1,pos[x],y); 189 end else 190 begin 191 read(ch); 192 if ch='M' then 193 begin 194 readln(ch,ch,x,y); 195 t:=lca(x,y); 196 writeln(max(solve_mx(x,t),solve_mx(y,t))); 197 end else 198 begin 199 readln(ch,ch,x,y); 200 t:=lca(x,y); 201 writeln(solve_sum(x,t)+solve_sum(y,t)-v[t]); 202 end; 203 end; 204 end; 205 end.