[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.

 

 

posted @ 2015-04-10 19:09  mjy0724  阅读(198)  评论(0编辑  收藏  举报