• 【初识】树上分块


    树上的有些问题是可以用树剖或者动态树解决的,但是他们有一个动同点就是:不连通。

    • 比如求u到v的路径权值和,或者最大值:

                    u到v可能对应了多个链,这多个链在对应的数据结构(假设是线段树)上面对应不同的区间。但是线段树上这几个区间的不连续并不影响我们得到答案。

                    (当然求子树的信息话是连续区间)

    那么如果我们遇到的问题要求区间连续呢,比如求u到v的路径上点的权值有多少种?如果不连续就得处理链与链之间的关系。显然这些点得待在一起,如果树剖很难维护链与链之间的关系。

    树分块,大概有这样的一些方法: 

    • 王室联邦分块法:可以保证每个块的大小和直径都不超过2√N1,但是不保证块联通 
    • DFS序分块法:首先是好写(毕竟转化成了序列问题),严格保证块大小√N,但是不保证直径,也不保证联通。处理子树信息比较方便 
    • size分块:检查当前节点的父亲所在块的大小,如果小于√N就把当前节点加入进去,不然新开块。块大小最坏√N,保证块内联通,还保证直径,多么优美啊可惜不能保证块个数(一个菊花图就死了)

     

    王室联邦分块,假设每个块的数量个数为[B,3B].

         如何分组可以看,裸题 BZOJ1086 王室联邦。 

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int const maxn=2010;
    int q[maxn],group[maxn],rt[maxn],top;
    int Laxt[maxn],Next[maxn],To[maxn],cnt,ans;
    int n,B;
    void init()
    {
        ans=0;  top=0;  cnt=0; 
        memset(Laxt,0,sizeof(Laxt));
    }
    void add(int u,int v)
    {
        Next[++cnt]=Laxt[u];
        Laxt[u]=cnt;
        To[cnt]=v;
    }
    void dfs(int u,int pre)
    {
        int Now=top;
        for(int i=Laxt[u];i;i=Next[i]){
            if(To[i]!=pre){
               dfs(To[i],u);
               if(top-Now>=B) { rt[++ans]=u; while(top!=Now) group[q[top--]]=ans;}
            }
        } q[++top]=u;
    }
    int main()
    {
        while(~scanf("%d%d",&n,&B)){
            int u,v; init();
            for(int i=1;i<n;i++){
                scanf("%d%d",&u,&v);
                add(u,v);add(v,u);
            }   dfs(1,0);
            while(top) group[q[top--]]=ans;  printf("%d
    ",ans);
            for(int i=1;i<=n;i++) printf("%d ",group[i]);printf("
    ");
            for(int i=1;i<=ans;i++) printf("%d ",rt[i]);printf("
    ");
        } return 0;
    }
    View Code

     

    再稍微介绍一下王室联邦分块是干嘛的:

         我们dfs,把子树中大于B的分为一组,剩余的(肯定小于B)上传分到父亲那组。由于父亲那组大于B,加进去小于3B。每一组即比较平均了,B的大小会影响空间和时间的优劣,需要根据题目给定的时间和空间,时间多空间小就B大,空间多时间少就B小。从而来决定B的大小。

         这样分块是为了莫队的排序,而不是预处理保存信息。比如,(u,v) 转移到(a,b),由于u和a或在一个组里面,即距离不太远,转移时间不太大。

    例题: Count on a tree II ,SPOJ - COT2,代码见这里

     求节点u到节点v路径上节点数值的种类。 此题有很多种牛逼做法,见此处的整理

    对于不要求在线的题,我们可以可以选择莫队算法:根据王室联邦分块来分块排序,按顺序转移得到答案,可以参考这里的代码

  • 相关阅读:
    20155305乔磊2016-2017-2《Java程序设计》第三周学习总结
    20155305乔磊2016-2017-2《Java程序设计》第二周学习总结
    20155305乔磊2016-2017-2《Java程序设计》第一周学习总结
    20155305乔磊第三次随笔
    乔磊20155305第二次随笔
    乔磊的第一次随笔
    20155302 2016-2017-2 《Java程序设计》第九周学习总结
    20155302 2016-2017-2 《Java程序设计》第八周学习总结
    20155302 2016-2017-2 《Java程序设计》第七周学习总结
    20155302 2016-2017-2 《Java程序设计》第六周学习总结
  • 原文地址:https://www.cnblogs.com/hua-dong/p/8275227.html
Copyright © 2020-2023  润新知