当一个问题可以分解成小问题时,我们一般可以采用分治算法,比如最简单的快速排序,就是分治算法的一个典型的应用。

  那么处理树的问题时,假设求解满足条件的点对儿个数,对于一个树来说,两个点对儿的存在只能有两种情况,就是点对之间的路径过根和不过根,那么对于不过根的情况递归做,对于一棵树只考虑过根的情况,计算就行了。

  以一个基础题为例子bzoj 2152

  http://61.187.179.132/JudgeOnline/problem.php?id=2152

  题的大概意思就是给定一棵树,求满足两点路径和为3的倍数的点对儿数量。

  现在说下具体的实现,首先3的倍数可以转化为边长和mod3为0的限制,假设我们任意取一点为根,将无根树转化为有根树,那么对于这棵树来说,我们可以由一遍dfs求出各个子节点子树中到根节点长度为0,1,2的数量,那么这样就比较好转移了,记录一个b数组,假设当前访问到p子节点,那么b数组中保留的为p点之前访问过的子节点中各个长度的数量,记录一个sum数组为当前p节点中的长度情况,那么由sum[i]*b[3-i]和sum[0]*b[0]来更新答案就行了。

  但是这样的话不能保证时间复杂度,在链的时候会退化到n^2。为了防止这样的情况发生,每次找根节点的时候不能任意选取,而是选取树的重心,这里的树的重心是指

去掉这个节点后,剩下的子树中点数最多的最小,直观的理解就是这个点附近的点比较密集,假设一颗数中有N个点,这样的点去掉后剩下的子树中的点数最多的不会超过floor(N/2),那么每一个节点为根时,这个子树中的节点会被访问一遍,因为每次找的是重心,每次都是floor(n/2),所以每个点最多会被访问log2N次,所以时间复杂度

是Nlog2N的。 

  具体的时间复杂度的证明可以去看2009年漆子超的论文《分治算法在树的路径问题中的应用》

找重心的过程类似于DP的过程

procedure getroot(u:longint);
varms, s, x, p, q                    :longint;i                                :longint;
begintop:=0;dfs_size(u,0);//这个操作是处理出子树的size值ms:=maxlongint;for i:=1 to top do beginx:=stack[i];s:=size[u]-size[x];q:=last[x];while q<>0 dobeginp:=other[q];if (ff[q]) or (p=yy[x]) then beginq:=pre[q];continue;end;if size[p]>s then s:=size[p];q:=pre[q];end;if s<ms then beginms:=s;root:=x;end;end;
end;

这道题的pascal代码

  1 /**************************************************************2     Problem: 21523     User: BLADEVIL4     Language: Pascal5     Result: Accepted6     Time:564 ms7     Memory:1360 kb8 ****************************************************************/9  10 //By BLADEVIL11 var12     n                               :longint;13     pre, other, len                 :array[0..40010] of longint;14     last                            :array[0..20010] of longint;15     l, top                          :longint;16     size, stack, yy                 :array[0..20010] of longint;17     ff                              :array[0..40010] of boolean;18     root                            :longint;19     b, sum                          :array[0..10] of longint;20     ans                                 :longint;21      22 function gcd(x,y:longint):longint;23 begin24     if x<y then exit(gcd(y,x)) else25     if y=0 then exit(x) else exit(gcd(y,x mod y));26 end;27      28 procedure connect(x,y,z:longint);29 begin30     inc(l);31     pre[l]:=last[x];32     last[x]:=l;33     other[l]:=y;34     len[l]:=z;35 end;36  37 procedure dfs_size(x,fa:longint);38 var39     q, p                            :longint;40 begin41     size[x]:=1;42     inc(top);43     stack[top]:=x;44     q:=last[x];45     while q<>0 do46     begin47         p:=other[q];48         if (ff[q]) or (p=fa) then49         begin50             q:=pre[q];51             continue;52         end;53         dfs_size(p,x);54         inc(size[x],size[p]);55         q:=pre[q];56     end;57     yy[x]:=fa;58 end;59  60 procedure getroot(u:longint);61 var62     ms, s, x, p, q                  :longint;63     i                               :longint;64 begin65     top:=0;66     dfs_size(u,0);67     ms:=maxlongint;68     for i:=1 to top do69     begin70         x:=stack[i];71         s:=size[u]-size[x];72         q:=last[x];73         while q<>0 do74         begin75             p:=other[q];76             if (ff[q]) or (p=yy[x]) then77             begin78                 q:=pre[q];79                 continue;80             end;81             if size[p]>s then s:=size[p];82             q:=pre[q];83         end;84         if s<ms then85         begin86             ms:=s;87             root:=x;88         end;89     end;90 end;91  92 procedure dfs_value(x,fa,lz:longint);93 var94     q, p                            :longint;95 begin96     inc(sum[lz mod 3]);97     q:=last[x];98     while q<>0 do99     begin
100         p:=other[q];
101         if (p=fa) or (ff[q]) then
102         begin
103             q:=pre[q];
104             continue;
105         end;
106         dfs_value(p,x,lz+len[q]);
107         q:=pre[q];
108     end;
109 end;
110
111 procedure solve(u:longint);
112 var
113     i, q, p                         :longint;
114
115 begin
116     getroot(u);
117     if top=1 then exit;
118     fillchar(b,sizeof(b),0);
119     b[3]:=1;
120     top:=0;
121     q:=last[root];
122     while q<>0 do
123     begin
124         p:=other[q];
125         if ff[q] then
126         begin
127             q:=pre[q];
128             continue;
129         end;
130         fillchar(sum,sizeof(sum),0);
131         dfs_value(p,root,len[q]);
132         for i:=0 to 3 do ans:=ans+b[i]*sum[3-i];
133         ans:=ans+sum[0]*b[0];
134         for i:=0 to 3 do inc(b[i],sum[i]);
135         q:=pre[q];
136     end;
137
138     q:=last[root];
139     while q<>0 do
140     begin
141         p:=other[q];
142         if ff[q] then
143         begin
144             q:=pre[q];
145             continue;
146         end;
147         ff[q]:=true;
148         ff[q xor 1]:=true;
149         solve(p);
150         q:=pre[q];
151     end;
152
153 end;
154
155
156 procedure main;
157 var
158     i                               :longint;
159     x, y, z                         :longint;
160     ans1, ans2                      :longint;
161     g                               :longint;
162
163 begin
164     read(n);
165     l:=1;
166     b[0]:=0;
167     for i:=1 to n-1 do
168     begin
169         read(x,y,z);
170         z:=z mod 3;
171         connect(x,y,z);
172         connect(y,x,z);
173     end;
174     ans:=0;
175     solve(1);
176     ans1:=2*ans+n; ans2:=n*n;
177     g:=gcd(ans1,ans2);
178     writeln(ans1 div g,'/',ans2 div g);
179 end;
180
181 begin
182     main;
183 end.

  比较好的例子还有bzoj 2599

    http://61.187.179.132/JudgeOnline/problem.php?id=2599

  大概的意思就是给定一棵树,求路径长度为K的点对路径上点数最小是多少。

  这道题与上道题的大题思路差不多,因为k给定的范围比较小为10^6,所以我们可以用一个数组来存每个长度最小用多少个节点,类似于上一题的b数组,然后也是不断地更新答案就行了。

pascal代码

  1 /**************************************************************2     Problem: 25993     User: BLADEVIL4     Language: Pascal5     Result: Accepted6     Time:16008 ms7     Memory:16928 kb8 ****************************************************************/9  10 //By BLADEVIL11 var12     n, m                            :longint;13     pre, other, len                 :array[0..400010] of longint;14     last                            :array[0..200010] of longint;15     l, top                          :longint;16     size, stack, yy, ll             :array[0..200010] of longint;17     ff                              :array[0..400010] of boolean;18     root                            :longint;19     b                               :array[0..1000001] of longint;20     old                             :longint;21     ans                             :longint;22      23 procedure connect(x,y,z:longint);24 begin25     inc(l);26     pre[l]:=last[x];27     last[x]:=l;28     other[l]:=y;29     len[l]:=z;30 end;31  32  33 procedure dfs_size(x,fa:longint);34 var35     q, p                            :longint;36 begin37     size[x]:=1;38     inc(top);39     stack[top]:=x;40     q:=last[x];41     while q<>0 do42     begin43         p:=other[q];44         if (ff[q]) or (p=fa) then45         begin46             q:=pre[q];47             continue;48         end;49         dfs_size(p,x);50         inc(size[x],size[p]);51         q:=pre[q];52     end;53     yy[x]:=fa;54 end;55  56 procedure getroot(u:longint);57 var58     ms, s, x, p, q                  :longint;59     i                               :longint;60 begin61     top:=0;62     dfs_size(u,0);63     ms:=maxlongint;64     for i:=1 to top do65     begin66         x:=stack[i];67         s:=size[u]-size[x];//68         q:=last[x];69         while q<>0 do70         begin71             p:=other[q];72             if (ff[q]) or (p=yy[x]) then73             begin74                 q:=pre[q];75                 continue;76             end;77             if size[p]>s then s:=size[p];//78             q:=pre[q];79         end;80         if s<ms then //81         begin82             ms:=s;83             root:=x;84         end;85     end;86 end;87  88 procedure dfs_value(x,fa,lz,dep:longint);89 var90     q, p                            :longint;91 begin92     if lz>m then exit;93     if dep>=ans then exit;94     if b[m-lz]>=0 then95         if b[m-lz]+dep<ans then ans:=b[m-lz]+dep;96     if (b[lz]<0) or (dep<b[lz]) then97     begin98         inc(top);99         stack[top]:=lz;
100         ll[top]:=dep;
101     end;
102     q:=last[x];
103     while q<>0 do
104     begin
105         p:=other[q];
106         if (p=fa) or (ff[q]) then
107         begin
108             q:=pre[q];
109             continue;
110         end;
111         dfs_value(p,x,lz+len[q],dep+1);
112         q:=pre[q];
113     end;
114 end;
115
116 procedure solve(u:longint);
117 var
118     i, q, p                         :longint;
119
120 begin
121     getroot(u);
122     if top=1 then exit;
123     top:=0;
124     q:=last[root];
125     while q<>0 do
126     begin
127         p:=other[q];
128         if ff[q] then
129         begin
130             q:=pre[q];
131             continue;
132         end;
133         old:=top+1;
134         dfs_value(p,root,len[q],1);
135         for i:=old to top do
136             if (b[stack[i]]<0) or (b[stack[i]]>ll[i]) then b[stack[i]]:=ll[i];
137         q:=pre[q];
138     end;
139
140     for i:=1 to top do b[stack[i]]:=-1;
141     q:=last[root];
142     while q<>0 do
143     begin
144         p:=other[q];
145         if ff[q] then
146         begin
147             q:=pre[q];
148             continue;
149         end;
150         ff[q]:=true;
151         ff[q xor 1]:=true;
152         solve(p);
153         q:=pre[q];
154     end;
155 end;
156
157
158 procedure main;
159 var
160     i                               :longint;
161     x, y, z                         :longint;
162
163 begin
164     read(n,m);
165     l:=1;
166     fillchar(b,sizeof(b),$ff);
167     b[0]:=0;
168     for i:=1 to n-1 do
169     begin
170         read(x,y,z);
171         inc(x); inc(y);
172         connect(x,y,z);
173         connect(y,x,z);
174     end;
175     ans:=maxlongint;
176     solve(1);
177     if ans>10000000 then writeln(-1) else writeln(ans);
178 end;
179
180 begin
181     main;
182 end.

转载于:https://www.cnblogs.com/BLADEVIL/p/3510482.html

树链剖分之点剖分(点分治)讲解相关推荐

  1. [学习笔记]树链剖分

    基本思想 树链剖分一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每条边属于且只属于一条链,然后再通过数据结构来维护每一条链. 一些定义 树链:树上的路径. 剖分:把路径分类为重链和轻链 ...

  2. 树链剖分 or 根号分治 + dfs序 + 树状数组 ---- CF1254 D. Tree Queries

    题目链接 题目大意: 问题转化: 很容易发现:假设修改的节点是vvv. 1.vvv的子树sonvson_vsonv​直接加上(n−size[sonv])n×d\frac{(n-size[son_v]) ...

  3. 树分治树链剖分相关题目讨论

    预备知识 树分治,树链剖分 poj1741 •一棵有n个节点的树,节点之间的边有长度.方方方想知道,有多少个点对距离不超过m 题解 点分治模板题.详见我早上写的http://www.cnblogs.c ...

  4. BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector

    题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...

  5. LG P3345 [ZJOI2015]幻想乡战略游戏(树的带权重心 + 树链剖分+ 动态点分治)

    题目 首先这个题看起来这个最小值不好在动态点分治时维护. (居然)可以转化. 最小值于树的带权重心处取到. 带权带的是点权. 树的带权重心是子树权∗2>=总树权子树权*2>=总树权子树权∗ ...

  6. 【CF487E】Tourists【圆方树】【树链剖分】【multiset】

    题意:给一张 nnn 点 mmm 边的连通无向图,点帯权,qqq 次操作: 修改一个点的权值. 询问两点间所有简单路的最小权值的最小值. n,m,q≤105n,m,q\leq 10^5n,m,q≤10 ...

  7. [ZJOI2015] 幻想乡战略游戏(树链剖分 + 线段树二分 + 带权重心)

    problem luogu-P3345 solution 这是一个带权重心的题,考察动态点分治.点分治?呵,不可能的,这辈子都不可能写点分治 我们重新考虑重心的性质:以这个点为根时,所有子树的大小不会 ...

  8. 【ZJOI2008】树的统计(树链剖分)

    传送门 Solution: 就是树链剖分入门题啦~ // luogu-judger-enable-o2 #include<bits/stdc++.h> #define N 30005 #d ...

  9. 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)

    题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...

  10. P1505 [国家集训队]旅游 树链剖分

    题目链接 题意:树上更新某一点权值,更新两点简单路径权值,查询最大,最小,和 思路:思路应该比较简单,就是树链剖分后用线段树维护区间最大最小以及区间和. 但是本题比较特殊的是给的边权,转化为点权即可. ...

最新文章

  1. 这些资源网站为什么能获得5万知乎大佬推荐,而我错失了什么吗?
  2. 新人python2和python3的区别_未明学院:Python2与Python3的主要区别
  3. C# WinForm给Button按钮或其它控件添加快捷键响应
  4. ubuntu 16.04 mysql5.7.17 开放远程3306端口
  5. idea springmvc_IDEA搭建SSM(spring+springmvc+mybatis)Maven项目的入门案例
  6. 转:Some interesting facts about SharePoint 2007 Search
  7. mac系统下为emacs设置中文字体,解决乱码问题
  8. d3.js 旋转图形_1.基础知识(3) Matlab绘制特殊的图形
  9. html5怎么给视频加字幕,怎么给视频添加文字 怎么用Premiere Pro cs6给视频中添加文字...
  10. Windows中MSOCache文件夹
  11. 如何设置正确的dns服务器地址,dns服务器地址如何设置
  12. perl 简明教程 perl教程集合
  13. jar启动出错:Failed to get nested archive for entry BOOT-INF/lib/activiti-core-common-dependencies-7.1.0
  14. Java和c的一些不同(一)
  15. java实训第二次作业//181021(个人所得税计算器;判断闰年与平年;个人作业展示系统(方法调用))
  16. 计算机技术离不开量子力学,高分子与计算机模拟
  17. 世态炎凉,冷暖自知-一名某易公司员工自述的裁员经历
  18. Android学习:线程同步之synchronized
  19. 携手吉林农信社 赛门铁克引备份新变革
  20. 用Python实现Excel表格的多对多批量替换

热门文章

  1. Vista下将Area效果应用到整个窗体
  2. iOS/Android React Native 配置教程
  3. 第三章 Goroutine调度策略(16)
  4. servlet,listener,filter,interceptor的关系
  5. 可变参数宏__VA_ARGS__和...
  6. centos+nginx从零开始配置负载均衡
  7. MSSQL备份及数据迁移
  8. 47页PPT,海量信息!用户画像架构、指标、标签、ETL、性能及案例应用一站通!(附PPT下载及视频 )...
  9. python psutil 获取命令历史_python中系统信息获取psutil使用
  10. 简单的Spring配置文件