zoukankan      html  css  js  c++  java
  • 【点分治+动态点分治】

    实在拖得太久了。

    先扔掉资料

    http://www.cnblogs.com/qt666/p/6597276.html

    http://www.cnblogs.com/nietzsche-oier/p/6604245.html

    http://blog.csdn.net/jiangshibiao/article/details/25738041?utm_source=tuicool&utm_medium=referral

    http://blog.csdn.net/ALPS233/article/details/51398629

    http://blog.csdn.net/vecsun/article/details/52808502

    http://www.cnblogs.com/fullpower/p/3869547.html

    分治的核心是尽量把一个整体分成接近的两个部分,这样递归处理可以让复杂度从n²变成nlogn。

    两个问题,如何区分和如何算答案。

    对于第一个问题,重心,然后就是找重心的方法,两个dfs,

    对于第二个问题,对于每个重心算当前块中每个点到重心的答案,然后由重心分开的块要把多余的信息去掉。

    求出重心的两个dfs

    第一,先算出每个点的子树大小

    void dfs_size(int x,int fa)
    {
        size[x]=1;
        repedge(i,x) {
            int too=e[i].toward;
            if (!vis[too] && too!=fa) {
                dfs_size(too,x);
                size[x]+=size[too];
            }
        }
    }

     第二,如果把一个点作为重心,它会把当前的联通块分成两个部分,子树和整个联通段的大小-子树,通过第二个dfs找到一个可以把图分成两快大小平衡的连通图

    void dfs_find(int x,int fa,int y)
    {
    //    printf("%d %d %d %d
    ",x,fa,y,sz[x]);
        msz[x]=y-sz[x];
        repedge(i,x) {
            int too=e[i].toward;
            if (!vis[too] && too!=fa) {
                dfs_find(too,x,y);
                msz[x]=max(msz[x],sz[too]);
            }
        }
        if (msz[root]>msz[x]) root=x;
    }

    //这里把root开成全局变量

    统计答案的more函数和dfs下去的calc函数

    more函数用于计算答案,当需要维护动态信息是,more函数用于一开始构建节点保存数据结构的初始化。

    LL more(int x,int len)
    {
        memset(num,0,sizeof(num));
        dfs_len(x,0,len);
        LL sum=0;
      /×计算过程×/
    return sum; }//update

    calc函数用于不断递归下去就子树

    void calc(int x)
    {
        int root;
        dfs_size(x,0);
        root=dfs_root(x,0,size[x]);
        ans+=more(root,0);   // 加入答案
        vis[root]=1;
        repedge(i,root) {
            int too=e[i].toward;
            if (!vis[too]) {
                ans-=more(too,e[i].v);  //减点不合法的答案,就是在同一棵子树上的
                calc(too);
            }
        }
    }

    如果子树的信息无法通过more直接减掉,可以分开写calc和more
    ,即

    void calc(int x)
    {
        dfs_size(x,0);
        root=0;
        dfs_find(x,0,sz[x]);
        vis[root]=1;
        repedge(i,root) {
            int too=e[i].toward;
            if (!vis[too]) {
                more(too,0,num[too],num[root]);
                /×计算×/
            }
        }
        repedge(i,root) {
            int too=e[i].toward;
            if (!vis[too]) calc(too);
        }
    }

    附上点分治会用上的dfs_len函数,用于记录长度信息

    void dfs_len(int x,int fa,int len)
    {
        d[++tot]=len;
        repedge(i,x) {
            int too=e[i].toward;
            if (!vis[too] && too!=fa) 
                dfs_len(too,x,len+e[i].v);
        }
    }

     

    对于动态点分治,也是由点分治引出来的,显然对于一个点,他最多属于logn个重心所在的块,重心之间又是有层次关系,可以抽象构造一个重心树,用数据结构就可以啦。

    比较麻烦的在于对于重心带的数据结构,他的域要控制得和这个块大小差不多,很多人用vec动态申请空间当bit用,我习惯用线段树。

    难点跟点分治一样,在于剔除在同一棵子树上的重复信息,所以要构建两个数据结构,一个做加的,一个做减的

    构建完后,对于询问或修改的某个点,依次访问它从里到外每个重心的统计信息。

  • 相关阅读:
    图床_shell命令passwd
    图床_shell命令usermod
    图床_shell命令groupadd
    图床_shell命令userdel
    图床_shell命令useradd
    图床_shell命令whereis
    图床_shell命令find
    图床_shell命令which
    图床_shell命令locate
    图床_shell命令free
  • 原文地址:https://www.cnblogs.com/Macaulish/p/6896168.html
Copyright © 2011-2022 走看看