zoukankan      html  css  js  c++  java
  • [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.
  • 相关阅读:
    struts1 Hibernate3初学
    java学习笔记
    改良程序需要的11个技巧
    SharePoint 2010 PowerShell 系列 之 应用总结
    PowerPivot for excel 100 Create KPI
    Sharepoint 2010 控件系统 之 扩展 SaveButton
    Entity Framework 5 一个模型多个关系图 期待已久了
    PowerPivot for Sharepoint 2010 配制及常见错误
    SharePoint 2010 PowerShell 系列 之 应用总结 (二)
    Sharepoint 2010 控件系统 之 TextField、LookupField、NoteField、RichTextField、SaveButton
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4415482.html
Copyright © 2011-2022 走看看