首页 > 其他分享 >动态点分治(点分树)

动态点分治(点分树)

时间:2022-10-22 13:56:26浏览次数:69  
标签:连通 动态 祖先 分治 点分 点分树 树上 节点

点分树(动态点分治)

点分治的核心思想在于依据重心划分子连通块,其良好的性质保证了最多只会分治 logn 层。有了这一特性,便可使用各种暴力计算答案。那么我们按照分治递归的顺序提一颗新树出来,易知树高是 O(logn)的,称之为点分树

具体的性质,在博客中有完整的阐述。概括如下:

  • **点 x 在点分树上的子孙集合就是原树中以 x 为重心(分治中心)时的分治区域,点分树上所有点的子树大小之和为 O(nlogn) **(每个点会被从根到它的路径上最多 logn 个祖先所统计)。这意味着,即便在每个节点上保存所有子孙的信息,空间复杂度只是O(nlogn)的。
  • 点分树的树高为 O(logn)。这意味着,如果要对某个点进行修改操作,直接在点分树上暴力跳父亲,改变 O(logn) 个祖先的子树信息即可。统计亦同理。
  • 对于点分树上 x 与 y 的 lca(或者说囊括连通块同时包含 x,y 的所有点分树节点中深度最深的那一个),易知在以此点为重心划分子连通块时 x,y 会首次被分割开来,因此该点必定在原树的 x,y 路径上。我们采集y对x的贡献,仅需从该lca上读取信息。
  • 点分树的一个子树总是原树上的一个联通块。在点分治过程中到达点u时,u的子节点数量在原树(当前树以u为根,除去已被标记的点)和点分树上是相同的,且一一对应,即,u在原树的不同儿子处在不同次级分治区域中内,获取来自某一儿子的信息,相当于获取来自对应的点分树子节点的信息
  • 节点x的分治区域被包含在y中,当且仅当y是x的祖先,也就是说,只有x的祖先记录了以x为终点的链,x的子孙节点的分治区域中不包含x,而其余的节点的分治区域则与x独立。点分树上,各分治重心所负责的路径互不重复

点分树的每个节点u,都可以看作是这样一棵树,它包含u的分治区域,并以分治重心u为根,负责统计(部分)经过u的路径。与根直接相连的各个子树,就是u的点分树子节点的分治区域。当一个点、一条边被修改,影响的是这棵树中的某一子树(联想DFS序),我们可以建立数据结构来维护这棵以u为根的树。

点分树的常数相当大,\(O(n(logn)^2)\)的复杂度甚至往往只能应付1e5而不能应付2e5,所以除了要细心降低常数外,我们在一个点分树节点上套数据结构时也得慎之又慎。由于每个节点所代表的分治区域大小总和不超过nlogn,我们在一个点分树节点上套数据结构,可以该结构的大小设置为以此节点为分治中心时的连通块大小(一般得再多预留一点空间)。

特别地,如果边权为1,那么从某一节点出发到其分治区域的任一点的链长,都不会超过连通块大小,我们可以使用静态表vector来O(1)地记录与读取某一长度的链的信息,而不是用map。考虑到连通块内的点数同样有限,我们可以在vector下再套vector来存放点编号,这都是允许的。

点分树和原树在结构上关联甚小,一定不要认为点分树上相邻节点在原树上也是相邻的。

能解决什么问题?

通常而言,点分树是一种维护端点链的工具,在具体问题中可以灵活运用。

一类典型的题目就是,指定树上一点,求与此点的路径长度满足一定条件的其他所有点的贡献之和,在需要时还得支持在线和带修。对于点分树节点u所代表的连通块中每个节点v(在进入这个连通块时,u为根),将端点链u-v的信息、贡献保存在u中(记作F1[u]),可以保证所有节点保存的链都是独立的,且可以组成树上的所有路径。对于指定的原树点x,以x为端点的路径,一定只能从“x到x在点分树上的祖先(含x本身) + 该祖先所记录的某条不位于x所在的子连通块的链(含该祖先单独本点,这经常被忽略)”组成(注意切勿把x在点分树的祖先与原树的祖先混淆)。假设v是u的子节点(点分树上),将v所代表的连通块(含有x)的所有点对v的父亲(这是确定且唯一的)的贡献保存在v中(记作F2[v]),在对x求解时额外减去这些贡献即可。

可以通过O(1)求LCA的方式来节省求两点路径的logn开销(题外话,树剖在一般情况下能与ST表不分上下)。不过考虑到我们一般只求点分树上节点到其祖先的距离,而祖先数量又不超过logn,我们可以对点分树执行一次预处理达到同样的效果。

long long query(x) //这是个大致模式参考
{
    long long res=F1[x];
    for(int y=x;fa[y];y=fa[y])
    {
        long long d=dis(x,fa[y]); //原树上的路径的距离,这个信息在很多题目要用到
        res+=F1[fa[y]]-F2[y];
    }
    return res;
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

点分树是对点分治过程的实质化,不难发现,点分治过程就是在这棵树上的DFS。

P2056] 捉迷藏 在点分树上,节点x的信息只保存在其祖先节点中,x受到改动也只会影响的祖先记录的结果,于是修改其祖先的信息、重新更新祖先的结果,并维护全局答案即可。对于x的某个祖先y,其记录的是在以y为根的分治区域树中,经过y的最长路径,因此它只在意各个子树的最长链,我们可以用multiset来维护。点分树中所有节点所记录的结果的最大值,就是全局解,我们还是用multiset来维护这n个分治重心的结果,当一个分治重心的结果改变时,重新维护全局解。

同样的,从点分树根节点到某一节点的决策路径,也可以看做是不断细分的过程,类比二分,这适用于一些有单调性质的问题。比如说越靠近某一个靶点,点值会越大/越小。具体地讲,我们确定目标节点一定在原树某一个连通块内,根据“点分树的一个子树总是原树上的一个联通块”这一重要性质,我们从点分树根节点出发,一路向下,不断地缩小连通块(如果原树中u的子节点v更优,可移动到v所在的连通块),最终就能找到靶点。

P3345]幻想乡战略游戏为例:

ll sea(int x)//传至此节点的点权和以及总贡献
{
    ll me=query(x);
    int vn=G[x].size();
    for(int i=0;i<vn;++i)
    {//在原图上做决策,在点分树上做移动
        if(query(G[x][i].first)<me) //本题(求点带权重心)的性质:非重心的节点,至少有一个邻节点的值小于自己
            return sea(Gx[x][i]); //我们在建树时,x在原树的每个邻节点恰好对应x在点分树的子节点,从而可以快速找到该邻节点所在的连通块的重心
        //由于单调性,一定不会回到x在点分树的父节点
    }
    return me;
}

那么我们在建树时,可以——

for(int i:G[x]) //遍历邻点
{
	if(vis[i]) 
    {   
        Gx[x].push_back(i); //x在点分树的父节点
        continue;
    }
    tot=sz[i];
    rt=0;
    get_root(i,0);
    Gx[x].push_back(rt);
}

标签:连通,动态,祖先,分治,点分,点分树,树上,节点
From: https://www.cnblogs.com/blover/p/16815969.html

相关文章

  • Dev-C++ 动态调试功能
    Dev动态调试今天发现了Dev还有这个功能,感觉十分神奇,于是记录一下设置要想使用动态调试,我们必须要先打开"产生调试信息"选项这是我们的页面,这是可以看到上方有一行......
  • ASP.net EF动态映射实体
    1、配置EF与建立实体模型这里不做过多介绍、主要介绍如何动态映射实体模型1.1、实现过程有很多种方式我们这里使用接口、然后扫描所有继承了该接口的实体类然后映射(也可......
  • apipost动态获取登录token,其他接口同步调用
    1、新增登录接口,接口返回值包含token信息接口信息   返回值   2、在登录接口的后执行脚本,添加环境变量 apt.environment.set("accessToken",response.js......
  • SSM综合案例之动态权限实战教程
    一、课程目标1.【了解】动态权限配置2.【掌握】AOP日志管理二、动态权限2.1将公开权限设置为无需认证即可访问<!--配置不拦截的资源--><security:httppattern="/l......
  • 基于Redis实现好友动态推送、附近商铺功能
    好友动态推送基于推模式实现探店笔记,一个人发布blog,在将blog保存到数据库的同时将blog发送到每个粉丝的收信箱中;收信箱按时间戳进行排序(类似于朋友圈);收信箱查询数据时按滚......
  • R语言单变量和多变量(多元)动态条件相关系数DCC-GARCH模型分析股票收益率金融时间序列数
    全文下载链接:http://tecdat.cn/?p=25957当您处理金融时间序列时,我们通常可以获得相对高频的观察结果。例如,每天进行观察是很常见的。事实上,现在可以获得每小时、分钟、秒......
  • 动态加载类注册到spring容器时的坑
    主要大坑(把目前遇到的写在这里,持续更新):动态加载的类无法使用CGLib代理,原因是动态加载的类无法继承,而CGLib是通过创建子类来代理的。spring中很多地方都是自动代理,无......
  • 还不清楚JDK动态代理?从简单例子到源码再到字节码讲给你听
    一、前言 Spring中的AOP思想就是对代理模式的经典运用,下面先讲讲代理模式的核心思想,以静态代理为例。二、静态代理示例下面有这样一个例子,委托人在遭遇利益受损的时候,可以......
  • 动态创建数组,一维和二维
    #include<stdio.h>#include<stdlib.h>voidOneDimensionVector(){//用来创建一维数组intn,i;int*arr;scanf("%d",&n);arr=(int......
  • antdv CheckableTag 动态显示
    exportinterfacedata{checked:boolean,label:string,}<templatev-for="(item,index)inlabelItems":key="index"><CheckableTagv-......