图论----树上问题
#
夕林山寸
这个作者很懒,什么都没留下…
展开
-
牛客等级之题N1(8.18场) A MMSet2 树的直径合并 dfs序维护lca
证明类似树的直径。类似于我上篇博客。#include <bits/stdc++.h>using namespace std;typedef long long ll;const int M = 3e6+7;int head[M],cnt=1;struct EDGE{int to,nxt;ll w;}ee[M*2];void add(int x,int y,ll w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=c原创 2020-08-19 17:47:45 · 120 阅读 · 0 评论 -
牛客练习赛67 F牛妹的苹果树 树上直径合并/ dfs序求LCA + 倍增维护最远点对
经典问题。证明类似于树的直径。两个点集所在的联通快合并,(其中可能会有交集)。其中合并后直径(点集中最远点对)为,两个联通快的直径对应的4个点,组合的6中情况的点对最大值。(即直径一定是这4个点中的2个,证明类似树的直径,从任一点出发,所达最远点是直径点,显然这4个点任一点出发,最远点一定还是这4个点中的一个)然后用dfs序维护lca(可以做到O1),倍增维护树直径合并即可#include <bits/stdc++.h>using namespace std;typedef原创 2020-08-19 17:35:26 · 145 阅读 · 0 评论 -
算法竞赛——进阶指南——acwing 364. 网络 e-DCC + LCA O(M+NQ)做法
#include <bits/stdc++.h>using namespace std;typedef long long ll;#define ls (o<<1)#define rs (o<<1|1)#define pb push_backconst double PI= acos(-1.0);const int M = 4e5+7;int head[M],cnt=1,head_c[M],cnt_c=1;struct EDGE{int to,...原创 2020-06-30 18:07:25 · 2694 阅读 · 0 评论 -
算法竞赛——进阶指南——acwng359. 创世纪 基环树+树形背包dp +环形dp
一个元素选,则限制其的元素必须至少一个不选。所以我们把元素指向限制其的元素。建出图。假如是棵树,则用树形dp即可。(类比经典树形dp舞池问题)但这是一颗基环树(即最多一个环,因为每个点有且只有一个入边,且是n个点,n条边)先找到每个联通块的唯一环。然后把环断开,当成一棵树进行树形dp。再考虑断开环的影响:比如断开x->y, 影响是:缺少了一条边x->y, 即x选,y不选的情况。那么我们让y固定不选,则x就可以选,且y其他儿子可任意选或不选。加个flag标记判断跑2..原创 2020-06-19 22:40:28 · 384 阅读 · 0 评论 -
P3177 [HAOI2015]树上染色 思维+树上背包
点之间距离不好直接求。可以转化为边的贡献。(感觉是经典思维套路了)然后就可以转化为经典树形dp题。(舞会那道)dp[i][j],以i为根的子树,染色j个黑色点,所有边的贡献。一个边u-v的贡献是:u这边黑点个数*v这边黑点个数*w+u这边白点个数*v这边白点个数*w然后树上分组背包即可。这题理论最坏情况下是ON^3的复杂度。但我们加上if(dp[x][j-k]!=-1)这句话后,有效执行次数就降到了 On^2 *T T 是一个小常数。(虽然循环执行了n^3,但很多是co.原创 2020-06-19 20:26:02 · 199 阅读 · 0 评论 -
算法竞赛——进阶指南——acwing 358. 岛屿 基环树求直径
由于每个点都要连一个边。最终图会分成若干个联通块,每个联通块n个点,n条边。即是一个基环树。求出每个联通块中任意两点距离最大值(即基环树的直径)求和即可。一般基环树的问题围绕环来处理。先把环看出一个点,就能转化为树上问题。基环树的直径分两类:(把环当成根节点)1.不在环上,在环的某个节点的子树中。2.经过环上2点x,y。并延申至x,y所在子树。即dis(x,y)+D[x]+D[y] .D[x]为dp求直径时维护的,x到其子树中点的最远距离。我们先求出基环树的环 :s1,s2.原创 2020-06-18 17:17:20 · 677 阅读 · 0 评论 -
算法竞赛——进阶指南——acwing 357. 疫情控制 二分+树上倍增+思维+贪心
一道树上难题!首先:时间肯定越长越好,我们可以二分转化为判规定时间是否可行从而简化问题。然后我们发现,一个节点肯定越靠近根节点其管辖的节点越多,也越优。在规定时间内,所有节点尽量往根节点靠近。执行完靠近后出现两类军队:1:停在根节点的儿子节点。2:停在非 根节点的儿子节点。第1类军队涉及到是否移动到根节点再移动到某个根节点的儿子节点。我们把根节点的儿子节点的集合设为S。先不考虑第一类节点移动的问题。只考虑第二类军队。dfs判断只用第二类节点是否能控制住根节点的某些儿子原创 2020-06-17 22:46:11 · 249 阅读 · 0 评论 -
算法竞赛——进阶指南——acwing 356. 次小生成树 kruskal + 倍增 +最值 lca
实现比较考验码力的一道题。思路比较简单:先建立出一颗MST,求出边权和ans,然后枚举非MST的边(x-y边权为w),与MST构成的环,求出换上最大边权mx,次大边权mc。若mx!=w,则次小生成树可能为:ans-mx+w;否则,次小生成树可能为:ans-mc+w;注意这里次大是严格次大。其实就是相当于求MST上 x-y路径中边权最大与次大值。可以类比距离求lca。 用倍增维护。然后就是经典合并最大次大。可以分类讨论或者直接开一个小数组sort。具体实现看代码。这原创 2020-06-17 15:37:14 · 228 阅读 · 0 评论 -
算法竞赛——进阶指南——acwing355. 异象石 dfn的性质+lca (简单的小证明)
比较难的一道题。题意是求连接标记点所需最小的边集。相当于求一个边集,恰好经过这些点,且边集最小。我们把这些标记点按dfn序(即dfs序)排列,发现相邻两个点的距离和(加上首末两点的距离和)刚好是上述边集的二倍。这个性质不好证,但容易观察得到。dfn本来就是按照dfs的遍历顺序的。下面简单证明一下:假设T是这些点的公共lca.那么边集一定进过T点。所以我们把T标记不会影响边集结果。易知:T点的dfn序一定是最小的。这些点按dfn序排序后,T在首位。然后我们以T为起点,按原创 2020-06-17 12:07:22 · 442 阅读 · 0 评论 -
Codeforces Round #649 (Div. 2) A-D
A:如果sm是k的倍数,肯定左右删最少的数。删到不是k的倍数的数即可#include <bits/stdc++.h>using namespace std;typedef long long ll;#define ls (o<<1)#define rs (o<<1|1)#define pb push_backconst double PI= acos(-1.0);const int M = 1e5+7;/*int head[M],cnt;void原创 2020-06-14 18:50:56 · 265 阅读 · 0 评论 -
算法竞赛——进阶指南 —— acwing354. 天天爱跑步 思维+树上差分+树上子树和减法应用
一道比较综合的树上差分题,比较考验思维。显然等差数列不好直接维护。先考虑什么情况下会观察到玩家:对于一条路径s-t对于上升路径s->lca(s,t),上的任意一点x:当:d[s]-d[x]=w[x] 时,这个人会被点x的观察员观察到。这样的话,对于每个点x,我们考虑所有人的起点s,当d[s]=w[x]+d[x]时,这个学生能被x观察到。这样就转化为了树上差分。(对于剩下的链 t -> lca(s,t) ,同理)对于一个人的路径中:s->lca(s,t)上的点原创 2020-06-10 12:51:39 · 344 阅读 · 0 评论 -
算法竞赛——进阶指南——acwing353. 雨天的尾巴 树上差分+动态开点线段树 +线段树合并
每个点开一个权值线段树(表示每个点每个种类的个数),x-y加上z种类,相当于让x-y区间的z种类+1。在树上就是 x的z种类+1,y的z种类+1,lca(x,y)的z种类-1,fa[lca(x,y)]的z种类-1.上述操作用动态开店权值线段树维护单点更新即可。每次最多更新4棵线段树。每棵线段树最多增加logz个节点 。总共会产生4mlogz个节点所以时空复杂度都是4mlogz最后dfs求子树和时,用线段树合并即可。如标题算法合并的模板题。三个算法都弄熟练这题就能手敲出来了。...原创 2020-06-02 22:33:14 · 175 阅读 · 0 评论 -
算法竞赛——进阶指南——acwing352. 闇の連鎖 思维方案数分析 + 树上差分
显然:主要边构成一颗树。次要边(x,y) 与主要边 x->y上的路径构成一个环。如果一条主要边a->b ,为与次要边构成环,则第一次斩断它,第二次无论斩断谁,都能把BOOS斩断。如果一条主要边a->b,只与一条次要边构成环,则第一次斩断它后,第二次必须斩断与它构成环的那条次要边。如果一条主要边a->b,同时与多条次要边构成环,则第一次斩断它后,第二次必须把这些与它构成环的次要边全部斩断,否则总有一条次要边可以代替主要边连接各点。但显然只能斩断一条次要边,所以这种情..原创 2020-05-26 22:02:42 · 332 阅读 · 0 评论 -
树上差分:边差分与点差分
1.边差分:一棵树,让x->y路径上的边权都加上w: d[x]+=w,d[y]+=w,d[lca(x,y)]-=2*w;最后求出F[i]:以i为子树,d的权值和。即i -> fa[i] 的边权。如下图:让6 -> 5 路径上的边权全部加1.d[2]=-2,d[6]=d[5]=1.其余为0然后F的值为:F[6]=F[3]=F[5]=1. 表示6 -> fa[6] 的边权为1,3 -> fa[3] 的边权为1,5 -> fa[5] 的边权为1,原创 2020-05-26 21:46:51 · 516 阅读 · 0 评论 -
tarjan法 Om 求m对点的LCA
算法步骤:1.dfs遍历整棵树2.遍历到的点且未回溯标记为1。(显然,当前点和其所有祖宗都是1,其余点要么是0,要么是2)3.访问过点且回溯后,标记为2。把他和父亲节点的集合并在一起(即用并查集优化,此时父亲节点的集合一定只有自身,且标记为1。这样操作的好处是,对于任意标记2的节点y,其get(y)一定是当前时刻它往上走第一个遇到的标记为1的节点)4.对于当前点x,其标记为1,对于标记为2的点y,他们的LCA为:y往上第一个标记为1的点。即get(y).遍历完整棵树,即可把所有x,y的l原创 2020-05-26 17:05:34 · 249 阅读 · 0 评论 -
倍增求LCA [HDU-2586] 模板 手敲更新
第三次敲这道题,这次直接手敲搞定。码力提升了不少#include <cstdio>#include<iostream>#include<algorithm>#include<queue>#include<cstring>using namespace std;typedef long long ll;const int M = 1e5+7;int head[M],cnt;void init(){cnt=0,memset(h原创 2020-05-25 23:06:10 · 152 阅读 · 0 评论 -
算法竞赛——进阶指南——acwing351. 树网的核 解法四: 单调队列优化到 On + 解法五:利用性质遍历On
对于直径1,2,3……,t我们选取i,j为路径d[k]表示,点k不经过1-t点,可达的最远距离。如下图:显然:i到j的偏心距:对于点i,j,不经过i,j上的点,且离其最远距离的点是1,t。对于点i+1 -> j-1 中的点k,不经过i,j上的点,且离其最远距离的点是:d[k]。综上 得:其偏心距等于:(根据前几篇博客的分析)i,j可以尺取得到(见解法二尺取贪心)前面的max(d[k]),用单调队列维护即可(单调队列维护区间[i-k,i],的最大值 ,...原创 2020-05-25 21:57:12 · 268 阅读 · 0 评论 -
算法竞赛——进阶指南——acwing351. 树网的核 解法三: 二分 nlogsum
偏心距显然具有单调性。二分偏心距mid。(存在一条路径使得其偏心距小于等于mid)然后选一条直径,端点为A,B。直径上的路径T:C,D。必须满足:CD<=S, AC<=mid,DB<=mid然后其他点到路径上距离最大不超过mid。On dfs判断即可#include <bits/stdc++.h>using namespace std;typedef long long ll;#define ls (o<<1)#defin...原创 2020-05-25 18:45:59 · 186 阅读 · 0 评论 -
P1099 树网的核 解法二——贪心 尺取降到O(n^2)
显然选择的路径越长,偏心距越可能变小(因为路径上点多了,其他点到路径上点最大距离就会变小)所以我们在直径上的点进行尺取优化。即可降到n^2#include <bits/stdc++.h>using namespace std;typedef long long ll;#define ls (o<<1)#define rs (o<<1|1)#define pb push_backconst double PI= acos(-1.0);const in原创 2020-05-25 17:39:57 · 175 阅读 · 0 评论 -
P1099 树网的核 (证明为何选一条直径即可) 一道很好的树的直径性质题 4种解法 这一篇是O(n^3) 性质分析+暴力
首先题目定义了点到路径的距离为:点到该路径上任意点最近的距离。然后给出偏心距的定义:一段路径F的偏心距为:其他点到这条路径距离的最大值。给出s,找出一条路径(必须在直径上)长度小于等于s的路径T,使其偏心距最小。题目要求必须在直径上,其实仔细分析发现,一定是在直径上,因为如果有一段不在直径上,离这一段路径最远的点,一定是直径的某个(不在路径上的)端点,但这段距离显然大于端点直接到在直径上路径的距离,不优,白白浪费s。找一条直径很好找,两边DFS即可(不清楚的可以看我之前blog的分.原创 2020-05-25 17:20:35 · 680 阅读 · 0 评论 -
树上 负权直径求法(包括打印路径) 树形DP+记录
思路在代码里。总的来说就是,记录每个点往子树,最大距离走哪,次大距离走哪。#include <bits/stdc++.h>using namespace std;typedef long long ll;#define ls (o<<1)#define rs (o<<1|1)#define pb push_backconst double PI= acos(-1.0);const int M = 1e5+7;int head[M],cnt;v原创 2020-05-22 22:55:00 · 344 阅读 · 0 评论 -
算法竞赛——进阶指南——acwng350. 巡逻 树的直径性质,(证明为什么K==2总有一条链选择直径)
先写下证明:(相信有人跟我一样不理解为什么K==2时第一条链必须选择直径,不能选两条不相交的次长链由于直径+相交的次长链嘛)看图:直径A-B先考虑如果不选直径,选两条次长链:A-2 B-3 (显然不选1-2,否则1-B就是直径,点4同理不选,而且为了更优,肯定选择不相交的两条,如果相交不如选择直径加其中一条长链)长度为: AD+D2+3E+EB;而选择直径+次长链:的长度为AD+DE+EB+3E+D2-DE与前者长度刚好相同(如果DE过长即3D+D2<DE则我们直接选取...原创 2020-05-22 19:43:54 · 320 阅读 · 0 评论 -
Computer HDU - 2196 树的直径 性质
树的直径最简单的做法:随便找一个的点dfs找离他最远的点p,然后再一遍dfs找距离p最远的点q。p-q即直径。下面给出简单的小证明:假设第一遍dfs找到了x,直径是u-v。那么离x最远的点要么是y,z,b,a这几个点中的一个。(分别对应几种情况)显然y和z,a不可能,因为dis(x,v)一定大于dix(y,x),dis(y,z),dis(x,a),否则,我们从u出发,离u的最远点就不是v了。对于b,也不可能,同上,dis(x,u)一定大于dis(x,b)否则,u-v就不是直径了。所以原创 2020-05-22 14:41:57 · 192 阅读 · 0 评论 -
CF1335F Robots on a Grid 思维+拓扑处理环。
5点多开始看题,10点半AC,除去1h吃饭。。其余都在调。。不过这次是自己硬刚出来的,没看题解,爽的不谈。这题思路还是比较好想的,主要是细节特别多。显然,所有环的大小和,即可以放的机器人最大数量。现在问题就在黑块上。我们观察这个图。是类似细胞的形状,专业点就是基环树。分支上的点进入环上会与一个点重叠(即,进入环时与这个点相遇)。我们对环上一个点进行逆向图BFS,对深...原创 2020-04-30 22:58:00 · 239 阅读 · 0 评论 -
ICPC Southeastern Europe Contest 2019 E. Game on a Tree 树上匹配问题
如果树能完全匹配,则先手必败(后手选先手的匹配的点)否则反过来(先手必胜:确定一个最大匹配,先手选非匹配的点,后手只能选最大匹配上的点,先手就对应匹配上)所以我们贪心找树是否是完美匹配即可#include <bits/stdc++.h>using namespace std;typedef long long ll;#define ls (o<<1)#...原创 2020-04-12 21:24:46 · 227 阅读 · 0 评论 -
Codeforces Round #629 (Div. 3) E - Tree Queries dfs序判祖先关系
惭愧,前几天刚学的dfs序判祖先关系都忘了用。。这题我们先把所有点都变成父亲节点(根节点不变),这样只需要判所有节点是否在一条链上。由于判断x是y的祖先:需要满足:st[x]<=st[y]<=ed[y]<=ed[x].即:一条链上的的所有点必须是相互包含的关系,一旦有个非链上的点,那么他一定与某个点不是祖先和孙子的关系,就会出现min(ed[])>max(s...原创 2020-03-27 12:51:26 · 360 阅读 · 2 评论 -
Benelux Algorithm Programming Contest 2019 I. Inquiry II 二进制枚举+树形DP
找无向图的最大独立集是个NPC问题优化只能优化常数,复杂度是O(n*2^n) 级别的。100必炸。这题有个很明显的提示,就是保证了边数[n-1,n+15]。赤裸裸的暗示你,枚举最多16条边上的点,删去这些边,转化成一个树来做,然后树形DP找最大独立集,这就是个经典问题了。删边的前提是,不会少算一些情况,由于每条边的两个点不能同时取。我们用二进制枚举每条边,不取哪个点。在树形DP...原创 2020-03-25 11:14:57 · 160 阅读 · 0 评论 -
Arab Collegiate Programming Contest 2015 A. Problem A. Christmas Tree 多个点的LCA
由上篇博客的性质,多个点的LCA等与dfs序最小的与最大的LCA。不懂得可以看看我上篇bolg,独家证明。。#include<bits/stdc++.h>using namespace std;const int M =1e5+7;int head[M],cnt;void init(){cnt=0,memset(head,-1,sizeof(head));}stru...原创 2020-03-20 17:44:12 · 351 阅读 · 0 评论 -
Luogu P3379【模板】最近公共祖先(LCA) dfs序+RMQ O1求LCA
这个方法求LCA可以O1查询。而且会有一些神奇的性质:st[x]<st[y]<=ed[y]<=ed[x],表示x是y的祖先。st是第一次访问节点的时间,ed是最后一次访问节点的时间两个节点的LCA等于min(st[x],ed[y])中间dfs序最小的那个节点。//也可以写成min(st[x],st[y]),min(ed[x],st[y]),min(ed[x],ed[y...原创 2020-03-20 12:09:24 · 583 阅读 · 0 评论 -
POJ 3321 dfs序+树状数组简单题
简单题,回顾dfs序,方便学dfs序+RMQ 求CA#include <cstdio>#include<cstring>#include<iostream>using namespace std;typedef long long ll;#define ls (o<<1)#define rs (o<<1|1)#def...原创 2020-03-19 20:48:01 · 106 阅读 · 0 评论 -
cf894 D .Ralph And His Tour in Binary Country 二叉树性质
题意的连边描述很容易想到线段树,而线段树是个二叉树。题意求的是,每次询问某个节点到其他所有节点的距离中,大于H的和是多少。由于是只加大于H的,所以不能换根.每次都要暴力查询。不过我们可以预处理出来一些东西。容易发现,预处理出某个节点到子树所有节点的距离很容易,求其中大于H的可以用二分查找。而二叉树最多logn层,每层n个节点,空间最大nlogn。所以直接建课树,节点存一...原创 2020-02-12 18:13:56 · 157 阅读 · 0 评论 -
P3398 仓鼠找sugar 树上路径相交判断 倍增求LCA
首先要知道倍增法快速求LCA,即任意两点间距离。类比RMQ。f[x][k]表示点x向上走2^k步 点的id。(即父辈2^k,x的父亲是f[x][0])先BFS或者DFS求出f[x][0]即初始化。然后DP一下。最后二进制拆分。即利用f数组快速让x,y向上寻找LCA。方法一:学习洛谷题解由于树上的独特性质:向上的路径只有一条判断AB,CD两条路径是否相交,我...原创 2019-10-07 21:07:34 · 325 阅读 · 0 评论