![](https://img-blog.csdnimg.cn/20201014180756919.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
点分治/点分树
点分治/点分树
TeJoy
这个作者很懒,什么都没留下…
展开
-
一类点分治和点分树相关问题的总结
一类点分治和点分树相关问题的总结 这些天刷了很多点分治和点分树的相关问题,来总结一下 首先这些问题是比较套路化的, 树上全路径问题,连通块问题的计数和判定,一般都是用到点分治/点分树。 统计的办法有两种,一种是考虑容斥,一般用于计数,一种是枚举子树统计。 前者好写常数较大,后者常数较小,细节较多 一般求路径长度<=k的数目,每个路径长度准确数目,常用第一种,一般还可能通过排序形成偏序关系,利用数据结构维护,常见的有树状数组、单调队列按秩合并维护 枚举子树统计的话,一般是这两种方法,要么当前根不保留,计原创 2021-04-16 15:48:45 · 169 阅读 · 0 评论 -
bzoj1095(点分治+堆)
bzoj1095(点分治+堆) 题意: 给一堆点,一开始全为黑点,每次取反一个点,问树上最远黑点距离 思路: 考虑建立点分树维护全局答案,显然对于分治重心来说,我们只用考虑子树对应最长链和次长链,由于要能删除,所以用两个堆组成可删堆来维护,一个维护当前点子树节点对父亲的贡献,一个维护所有儿子的前一个的最大值,再用一个全局堆维护,修改挺多细节的,自己当端点的情况得考虑,0也得考虑,具体看代码吧,只能说这题太阴间了维护起来,直接存份板子了, 另外如果把优先队列换成pbds里面的二叉堆可以快一半,直接过了洛谷最后原创 2021-04-16 15:43:46 · 94 阅读 · 0 评论 -
gym101234 D (点分+FFT)
gym101234 D (点分+FFT) 题意: 问树上随机点分治的点数期望 思路: 考虑枚举任意两个点,u对v有1的贡献当且仅当v第一个删除,设距离为d,概率是1(d+1)\frac1{(d+1)}(d+1)1,转化一下就是树上所有长度的路径数 cnt[i]i+1\frac {cnt[i]}{i+1}i+1cnt[i],但是统计每一种路径的条数我们无法用桶来统计,O(n2)O(n^2)O(n2),事实上这是卷积的形式,所以容斥统计用FFT维护即可,为了方便,边数+1即可,注意FFT是卷积过程 ,而这题原创 2021-04-16 15:42:35 · 131 阅读 · 0 评论 -
bzoj 4372(点分树+动态开点线段树
bzoj 4372(点分树+动态开点线段树 题意: 1.将树上与节点x距离不超过d的节点加上w 2.单点询问 思路: 多次与某点相关的连通块问题,点分树套路题 每个点建两颗权值线段树,一个维护自己分治区域中对应距离的标记,一个维护自己对父亲分治区域对应距离的标记,计算的时候容斥一下就好了,非常套路 #include<bits/stdc++.h> #define ls lc[p] #define rs rc[p] #define lson lc[p],l,mid #define rson rc[原创 2021-04-15 13:25:07 · 127 阅读 · 0 评论 -
bzoj3924(点分树
bzoj3924(点分树 题意: 1.树上找点uuu使得∑dis(u,v)∗u\sum dis(u,v)*u∑dis(u,v)∗u最小 2.单点修改点权 思路: 考虑uuu为当前决策点,对于其儿子vvv,移向其儿子的权值改变是(−sum[v]∗edge[i]+(sum[u]−sum[v])∗edge[i])(-sum[v]*edge[i]+(sum[u]-sum[v])*edge[i])(−sum[v]∗edge[i]+(sum[u]−sum[v])∗edge[i]) 改变小于0的时候,sum[u]<原创 2021-04-15 11:48:14 · 104 阅读 · 0 评论 -
cf293 E(点分治+树状数组)
cf293 E(点分治+树状数组) 题意: 统计边数<=L且边权重<=w的路径数 思路: 显然用容斥点分解决,按照w排序后是单调的,然后用树状数组维护l的数量即可,时间复杂度O(nlog2n)O(nlog^2n)O(nlog2n) #include<bits/stdc++.h> #define fi first #define se second using namespace std; typedef long long ll; typedef pair<ll,int&g原创 2021-04-15 11:16:33 · 151 阅读 · 0 评论 -
bzoj3730 (点分树
bzoj3730 (点分树 题意: 1.查询距离x点为k的点的权值和 2.单点修改第x个点的权值 强制在线 思路: 带修且多次询问距离某点 建立点分树维护,每个点开两个树状数组,一个用于维护当前分治区域对自己的贡献,一个维护对父亲的贡献,更新和维护从当前点在点分树上条根即可 注意计算的时候容斥,点分树的老套路了,算上本身后,减去当前对父亲的贡献,算上父亲自己的贡献,注意对于每个分治区域,树状数组的大小,一个是前一个分治子树的大小,一个是自己的分治子树的大小,为了方便,我都开成了上一次的大小,此外,树状数组需原创 2021-04-15 11:05:42 · 103 阅读 · 0 评论 -
libreoj 6145(点分树)
libreoj 6145(点分树) 题意: 给一你一颗树,多次询问某点到编号为[l,r]的最短距离 思路: 多次询问某点的连通块问题,显然点分树套路题 点分树的题一般都是一个点维护2个数据结构,一个维护自己分治区域对自己的贡献,一个维护对父亲的贡献,这里直接暴力维护两颗线段树就好了,下标就是标号。时空间复杂度O(nlog2n)O(nlog^2n)O(nlog2n),所以数组要开大点,此外初始值记得标为INF 这里有一个错误我要注意,欧拉序求LCA后,原树两点间的距离得额外求!!!! #include<原创 2021-04-15 10:11:05 · 84 阅读 · 0 评论 -
Libreoj 2179(点分治+线段树合并
Libreoj 2179(点分治+线段树合并 题意: 给一颗树,边有颜色,连续颜色的边权只出现一次,问所有路径边数在 [L,R]间路径权值的最大值 思路: 限制了路径边数,显然点分治,但是用容斥和枚举子树的方法我都只能口胡出n2lognn^2lognn2logn的做法,比如对每个颜色开一颗线段树,下标维护边长,这样每次到一个子树的时候,我们都得枚举前面所有的情况,事实上我们只关心前面的颜色和它是否相同 所以对当前子树按颜色排序形成偏序关系,然后对和当前颜色相同及不同的分别开一颗线段树,当前子树做完就直接在两原创 2021-04-15 10:02:55 · 118 阅读 · 0 评论 -
codeforces 715C(点分治+逆元
codeforces 715C(点分治+逆元 题意: 给一个n个点的树,问多少条路径满足边权连成的数%M==0 思路: 考虑点分治按容斥的写法计数,这题细节很多。 首先x1表示从根下来的路径,x2表示上去的路径,维护就很简单了 x1∗10(dep2)+x2=0(modm)x1*10^{(dep2)}+x2=0(modm)x1∗10(dep2)+x2=0(modm) 我们维护将x2加进桶里面,查询前面的数即可,这里有一些细节注意的是,我们得考虑端点,在分治重心的位置的时候,统计重心为端点的两条路径,具体实现标原创 2021-04-15 09:50:13 · 214 阅读 · 0 评论 -
gym102452 (点分治)
gym102452 (点分治) 题意: 点有点权,问树上路径数使得路径点权能构成一个多边形 思路: 香港区域赛的一题,当时vp的时候还不会点分,现在会了根本就是煞笔题嘛… 显然是问2∗mx<sum2*mx<sum2∗mx<sum的路径数,由于枚举子树的时候要分类讨论,所以我们用容斥方法计数,存下从分治重心出发的路径。 按照mxmxmx排序后,固定最大值枚举,假设枚举的两条链分别为x1x1x1,x2x2x2,由于根算重了,则转化为 2∗mx<x1+x2−rt2*mx<x1+x2-原创 2021-04-15 09:35:04 · 138 阅读 · 0 评论 -
hdu5909 (点分治+dfs序上树形DP
hdu5909 (点分治+dfs序上树形DP 题意: 问你全部点权异或为0~k的子树的数量 思路: 连通块问题,显然统计要包含所有的连通块,连通块问题可以考虑点分,点分过程中以分治重心为根即可以不重不漏包含所有连通块。 所以我们暴力固定分治重心为根即连通块中必选点,考虑一个点选了,其儿子才能选,否则其儿子不能选,这种连通块依赖问题,可以用dfs序转为树上dp 对每个分治区域做dfs序, dp[i][j]dp[i][j]dp[i][j]表示当前连通块dfs序上前i个点决策完,异或和为j的方案数, 下一个点要么原创 2021-04-15 00:26:13 · 349 阅读 · 1 评论 -
hdu5977 (点分治+状压
hdu5977 题意:点有物品,问树上包含所有物品的路径 思路: 显然状压,采用点分的第二种方式统计 当前的桶保留除当前根外的状态,统计的时候再算上当前根就好了,这样路径至少计算两个点,考虑统计的时候,统计当前集合的子集的补集数量,注意不会枚举到空集,所以要统计全集的情况,此外,要统计端点的情况,所以d[0]=1d[0]=1d[0]=1; 最后单独点成立的条件只有k=1k=1k=1的时候,特判一下即可 注意还得*2 这样的统计方法比容斥常数小 #include<bits/stdc++.h> us原创 2021-04-15 00:07:25 · 119 阅读 · 0 评论 -
bzoj 4016 (点分治)
bzoj 4016 (点分治) 题意: 求图上从1点出发的最短路径树上,最长的包含K个点的简单路径长度,长度为该最长长度的数量 思路: 大缝合题 最短路径树就跑最短路后排序一次再根据最短路径跑一次生成树就好了。 恰好为k个点的路径显然考虑点分第二种写法 用桶维护指定点数的最大长度以及相应的最大数量 维护过程其实就算是在分类讨论是否更新最大值而已 这里我当前子树是除了根的都统计到桶里,保存的时候则是保存包括根的路径 这样需要注意的是一开始前面的桶必须要初始化只有单个点的情况,这样才能统计到以重心为根的贡献,具原创 2021-04-07 22:57:01 · 129 阅读 · 0 评论 -
hdu 4812 (点分治+逆元)
hdu 4812 (点分治+逆元) 题意: 找出一条路径,点上乘积模1e6+31e6+31e6+3的值=k,(u,v)字典序最小 思路: 树上路径判定问题,显然可以用点分的第二种写法解决。 a[i]∗a[j]≡k(mod(1e6+3))a[i]*a[j]\equiv k(mod (1e6+3))a[i]∗a[j]≡k(mod(1e6+3)) 对于这种点权相关点分治的第二种写法,在分治重心统计的时候可以先把根忽略,存储不包含根的路径(点权转边权,根点权消失),先统计点数>=2的路径,最后再单独考虑单点贡原创 2021-04-07 22:29:17 · 156 阅读 · 1 评论 -
bzoj 2599(点分治
bzoj 2599(点分治 题意: 求所有路径中,路径权值和为k且边数量最小 思路: 路径问题显然点分,权值是恰好=k,所以可以采取第二种点分写法,用桶记录指定权值的最小边数,然后枚举的过程中暴力统计即可 但是要注意两点 1.权值为0的要初始化,端点是其本身 2.同时要在点分完之后重新初始化改过的边 #include<bits/stdc++.h> #define fi first #define se second using namespace std; typedef long long原创 2021-04-07 21:15:54 · 154 阅读 · 0 评论 -
poj1741(点分治 路径长度<=k路径数量
poj1741(点分治 路径长度<=k路径数量 题意: 给一颗n个点的树,问路径长度<=k的路径有多少 思路: 点分模板题,因为是计数+<=k的路径,所以采用容斥写法,容斥写法常用加上排序等操作,这里路径长度排序后具有单调性,所以直接统计就可以了 当然还有别的如树状数组之类的统计方法,但是感觉没必要 时间复杂度O(nlog2n)O(nlog^2n)O(nlog2n) #include<iostream> #include<cstdio> #include<cs原创 2021-04-07 21:06:57 · 142 阅读 · 0 评论 -
bzoj 4860 (点分治+线段树合并)
bzoj 4860 (点分治+线段树合并) 题意: 给你一颗树,边有颜色对应权值,连续段权值只算一遍,问边数在[l,r]之间的路径中,路径权值的最大值 思路: 树上路径问题,带边数限制。 先考虑点分。求最值,采用点分第二种写法,逐一枚举子树合并 一开始想着对每个颜色都开一颗线段树,查的时候再遍历前面的一遍 显然这个做法是O(nlog2n)O(nlog^2n)O(nlog2n)的。 能否避免再遍历呢? 其实我们发现,我们只关心当前子树是否相同和不相同的两类颜色。可以通过排序当前子树颜色,颜色上形成偏序关系,就原创 2021-04-07 16:32:59 · 94 阅读 · 0 评论