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

    一搬都是动态修改点权时我们使用动态点分治来保证时间复杂度.

    这里说一下深刻的理解,首先建出点分树并不难我们只需要记一个fa甚至不需要记儿子就能维护出来这样的一棵树.

    为什么要维护这样的一棵树下面根据例题具体论述:

    [bzoj3730震波](https://lydsy.com/JudgeOnline/problem.php?id=3730)

    1. 每次查询距离x距离不超过y的点权之和.

    2. 点权有修改.

    3. 强制在线.

    如果光有1怎么办我们可以考虑一下换根,好像父亲的信息很难维护 不可行。

    点分治?好像也不行,有一种做法是每个点维护主席树然后再暴力向上跳统计答案+去重。

    其实如果没有强制在线这类似于三维数点问题,由于我学艺不精不会数点...

    好像我们第二种思路就是复杂度高了一点,那么细致的讲下一下第二种思路吧.

    每个点维护其子树内距离为d的点权和具体的我们可以使用线段树合并来保证复杂度.

    考虑一下查询首先是在x处查询,x暴力跳父亲在父亲处查询此时注意容斥把x处y-1的距离减掉即可.

    那么修改呢?同样是暴力修改点权但是好像这里空间开销过大 时间也是如此极其不优秀。

    原因?我们可能要从一条链的底部跳到链的顶头很难受。

    其实我们这样做的原因只是为了检索到所有的答案罢了.

    所以可以用点分树这棵树来进行暴力检索答案的过程由于树非常的平衡logn 所以时间和空间上都是可以承受的。

    具体的这能完全体现出检索答案的过程么?

    在x点询问 我们直接在点分树中的x点所维护的主席树中查询,然后跳点分树的父亲,直到根。

    正确性 这里先不考虑容斥,就是说其实它的思想是一个联通块一个联通块搞。当前我这个点所处的点分树的位置代表了以这个点为根时的状态。我们这个点跳父亲了之后表示的是这个联通块之外的点进行统计答案显然的是此时的意思是我们这个点跳出来统计答案而本身的联通块我们假设其消失,就是这样我们每次统计完一个联通块就假设其消失然后最终我们发现把所有的点都扫了一遍。正确性显然。

    我们利用的不过是点分树log层这个优秀的性质。

    那么你可能会发问我们在点分治的时候维护这个过程不就好了?带修呢?按照时间顺序一起跟询问放到vector里。

    不得不说这样很难写我没写过不知道 但是这道题是强制在线的/cy

    考虑容斥的事宜,我们发现在更新我们这个点的线段树也同时会更新点分树上父亲,如果两次查询显然有可能会重复。

    但是重复的也只是我们这个点的集合里面的某些元素我们考虑把这些元素在我们这个点直接减掉。

    也就是说我们需要另开一颗线段树表示和父亲里面重合的元素,距离自然还是到父亲的距离了。

    这样这道题就做完了.

    啊啊啊啊 卡了一下午常数啊 原因线段树里能不pushup就不要pushup 你手贱写pushup干啥啊直接在来的时候累加就行了.

    啊啊啊啊 加register啊 求LCA的时候常数小一点别定义那么多变量什么的。真是人傻常数大。不过痛彻我的心扉。

    再上一道例题深刻理解一下点分树:

    [ZJOI2007捉迷藏](https://www.luogu.com.cn/problem/P2056)

    树上有黑点和白点 求两个黑点之间的最长距离。

    其实就是动态维护树的直径 线段树做这个要好一点 这里采用点分树.

    这道题做法很多:点分树 线段树维护括号序列 线段树维护直径 LCT...

    都很神仙,我都不会。这里简单分析一下点分树的做法:

    首先我们要知道为什么使用点分树,显然静态的问题我们可以采用点分治来完成这个问题,因为待修改我们考虑点分树来进行动态修改。

    我们要知道点分树上每个点要维护什么 显然要自己子树内合并的答案就行了要维护这个得知道自己子树内的最大和次大值。

    但是出现问题了这两个值可能出自一个父亲和儿子他们真是距离并不是这样的。

    我们很难进行合并两边的子树,但是 其点分树上的父亲可以 我们知道点都是由儿子调到父亲的 所以我们在其父亲处合并就可以保证是分属在两个不同的子树之中了。

    我们发现所有叶子节点不可能对答案有贡献 所以我们只需要每个点维护其到其父亲的最大距离即可 在父亲处再维护一个所有儿子的最大值的堆就行了。

    需要注意的是如果自己本身也是黑点那么还要多插入一个0.

    值得一提的是因为每个点都可能被删除所以还需再维护一个伴生堆就行了...

    挺ex的 需要开O2才过 我常数就那么大么!

    挺难写的 尽管我知道了思路 瞄了两眼题解才会写我tcl...加油~

    [幻想乡战略游戏](https://www.luogu.com.cn/problem/P3345)

    这道题目的意思是让我们寻找带权点重心。但是点权待修改。

    显然和边权无关,我们如何动态维护重心是问题的关键.

    每次修改重心都会可能会移动且没有方向性 如果我们采取暴力dp复杂度较高.

    这时我们发现了 点分树的性质 修改的话是logn 我们能否利用其动态找重心是关键。

    这道题目利用动态点分治思想难度就很高了。非常抽象的求解。

    我们发现 我们想要logn的修改 从而快速利用点分治的性质求解答案。

    不妨我们先得出用点分治如何求答案 套到点分树上我么你就可以logn出解了.

    在原树上我们发现 以x 为根 那么y比x优当且仅当 sum[y]<<1>sum[x] 这里sum[i]是指以i为根的子树内的权值和。

    我们发现在树上瞎跑就能得到答案.

    同样这个sum可以拓展到点分树上 那么我们在点分树上跑也是可以的。

    首先我们把答案定到根 发现点分树上sum[v]<<1>sum[x]那么x的那边子树一定都不是最优解。

    我们去v的点分树上再次找答案即可。就这样递归下去,是存在一定问题的 就是x的令一侧子树在v里v此时要动态的修改。

    于是我妥协了 这种方法 我很难想出来到底是怎么绑定动态修改再修改回去的。

    考虑一种更简单的判定方法我们想要知道如何判定答案是否在一个分治中心的子树中。

    这样就可以保证递归log层 我们每次都check一下和当前中心相连的那20个点 看谁最小了 那么答案就在某个分治中心之中。

    我们显然可以证明这样做是正确的。保证了复杂度,关键在于如何找答案 暴力跳父亲+简单容斥即可解决。

    终于A掉了 太难了 我觉得 这道题用动态点分治太差劲了 强行套点分治的性质。

    不过也太妙了 这都能用点分树来解决。分治果然无敌。

    一句话这题nb.

  • 相关阅读:
    五、生产者消费者模型_ThreadLocal
    四、多线程基础-线程池的创建和使用
    spring根据beanName获取bean
    spring容器的功能扩展
    机甲大师S1机器人编程学习,Windows 10 安装Scratch和简单实例学习
    如何建设高可用系统
    详解Condition的await和signal等待/通知机制
    从源码角度彻底理解ReentrantLock(重入锁)
    MySQL 分库分表及其平滑扩容方案
    机甲大师S1机器人编程学习
  • 原文地址:https://www.cnblogs.com/chdy/p/12292786.html
Copyright © 2011-2022 走看看