DFS序 DFS 序就是DFS得到的序列(简洁明了) DFS 序擅长处理子树的问题, 可以发现 子树是这个子树根节点入栈到出栈的整个序列 DFS 序把子树修改转化为了区间修改的问题。 「HAOI2015」树上操作 要对一个树进行操作, 支持点修改, 子树修改, 查询某个节点到跟节点的距离。 对于树剖就是版子
1.0 定义 其实本质也是一种暴力。。 回忆点分治的过程:每次找到当前子树的重心,处理所有经过该重心的路径的答案,然后将其删去,分裂成一些子树,再分别进去递归。 把点分治的过程离线下来,将当前树的重心与上一层的树的重心连边,这样就可以得到一棵树,我们称之为“点分树”。 1.1 应用范围
定义: 边权为原图最小割的一颗树,对于树上的一条边\((s,t)\),去掉\((s,t)\)后,最小割树上两颗子树为割后的两个点集。 构造: 考虑分治,先任意选择两点,求得最小割为其边权,然后将两边递归操作,注意求最小割的并非在子集上做。 性质: \((x,y)\)的最小割为其在树上的两点路径的最小值。
点分治 [SDOI2016]模式字符串 点击查看代码 [JOISC2020] 首都 点击查看代码 点分树
\(\text{P2664}\) 树上游戏 算法:点分治、树上差分 题目: 有一棵树,树的每个节点有个颜色。给一个长度为 \(n\) 的颜色序列,定义 \(s(i,j)\) 为 \(i\) 到 \(j\) 的颜色数量。以及 \[sum_i=\sum_{j=1}^n s(i, j) \]求所有的 \(sum_i\)。 \(1\leq n,c_i\leq 10^5\) 题解: 这里有两
众所周知,树上背包如果上下界都卡紧了复杂度会是 \(O(nm)\),下面来进行这一点的证明。 以下设节点总数为 \(n\),背包容量最大是 \(m\)。 合并两个泛化背包的复杂度为 \(O(s_1s_2)\),其中 \(s_1\) 是第一个泛化背包的容量,\(s_2\) 是第二个背包的容量,但这个复杂度是在背包容量不设上限的
考点 基环树 树链剖分 树上DP 树上分治 点分治 NOTE 1.分治前求dep的时候忘记dep[rt]=0 流程1(适用于计数等容易去重的) 找根 处理过当前根到子树内的路径(加入根到根的路径,用两条到根的路径合并) 去掉不合法(统计同一个子树出来到当前根的两条路径),继续分治 流程2(适用于
题目描述 给定一个大小为 nn 的树,它共有 nn 个结点与 n - 1n−1 条边,结点从 1 \sim n1∼n 编号。初始时每个结点上都有一个 1 \sim n1∼n 的数字,且每个 1 \sim n1∼n 的数字都只在恰好一个结点上出现。 接下来你需要进行恰好 n - 1n−1 次删边操作,每次操作你需要
来自\(\texttt{SharpnessV}\)的省选复习计划中的树上问题。 树上问题是\(\rm OI\)中必考的难点。 P5018 [NOIP2018 普及组] 对称二叉树 判断带点权有根二叉树是否同构。 因为有根且是二叉树,这极大简化了判断同构的过程。 我们定义函数 bool check(int x,int y) 判断以 \(x/y\)
题目大意: 给定一棵树,求出一对起点和终点,使得从起点随机游走,到终点停下的期望步数最多,输出这个期望步数 solution: 其实不难 树形 \(dp\) 首先,另 \(f[x]\) 表示从 \(x\) 点走到他父亲的期望步数 它有可能先走到某个儿子里,然后再回来,也有可能直接走到它的父亲 因此: \[f[x]=\frac{1}{|
#6429 简单无向图: 图的区间连边,使用线段树矩形 +1 结合找 0,用 Boruvka 算法求连通块数量。 #6433 金色飞贼: 将平面上的三角形投影到一条线段上后再利用 set 进行计算。 #6435 inversion: 树上 map 启发式合并。 #6437 turing machine: 数位置的移动转为平面直角坐标系上点
典型树上差分例题 前缀和差分讲解 tarjon_lca 例题: Max Flow P 个人感悟: 1. tarjon 感觉tarjon算法巧妙的利用了数据结构--并查集,将直观的寻找lca 的思想方法实习出来,在实现tarjon算法的过程中我对dfs的理解又加深了,dfs“去”和“回”的代码空间可以实现不同的功能顺序; 2. 树上差
操作 1 :把某个节点 x 的点权增加 a 。 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。 操作 3 :询问某个节点 x 到根的路径中所有点的点权和。 树剖板子 const int N=1e5+79; int a[N],b[N]; int n,m; struct graph{ int head[N],tot,next[N<<1],ver[N<<1]; inline v
传送门 刚了四个小时并且没有任何用处 一开始尝试按位拆开考虑贡献,但发现极难DP 想了trie树但感觉trie树只能处理两个数的相对关系,于是就没细想 然后正解扔到trie树上了 思路是枚举 \(k\),用trie树处理 \(i\) 和 \(j\) 发现比较大小时我们只需要考虑两者的最高不同位 两个数比较大
树上莫队复习 被开业 D 了所以就来写 md 定义 树
一、题目 我们认为 \(x\rightarrow y\) 的简单路径是好的,当且仅当路径上的点最小的是 \(x\),最大的是 \(y\) 给出一棵 \(n\) 个点的树,求出好的简单路径条数。 \(n\leq 2\cdot 10^6\) 二、解法 很容易写出暴力点分治,但是因为需要解决二维偏序问题所以是 \(O(n\log^2n)\) 的。 首先考
还没整完明天再说,靠不小心点了发布、、 Link 某些废话 devinwang勒令我们补掉CSP2019的题 /youl 看了半天题解脑子里还是浆糊,退役人是我这样的。 这篇题解写的非常清楚,我写这个只是给我自己看。 题意 现在给你一棵树,数字 \(i\) 在编号为 \(p_i\) 的节点上。 每次删除一条边,删边时
奇怪的树上背包,而且带了一些玄学。借这篇题解详细地总结一下树上背包的做法。 题面 链接 给定一棵 \(n\) 个点的树,给定正整数 \(k\) , 在树上找出 \(k\) 个不同的点,设为\(A_1, A_2...A_k\),使得 \(\sum_{i=2}^{k}{dis(A_i,A_{i-1})}\) 最小,输出这个最小值。其中 \(dis(x, y)\) 表示
先观察题目性质 考虑形式化满足哪些条件的点被选( update / query ) 我们观察一张图: 对于上图区间 \([3,10]\),选的的点依次为:\(14,5,6,7,8,17\) 其实就是我们把 \(l~r\) 点的树上路径拿下来 根据 \(lca\) 把树分为两部分 我们把左链和右链分开考虑 对于左链: 先对于节点 \(l\) ,我们
点差分 让x到y所有的点++; sum[x]++,sum[y]++,sum[lca(x,y)]--,sum[fa[lca(x,y)][0]]--; 边差分 让所有的边下降到点,每个点代表与其父亲连接的点 sum[x]++,sum[y]++,sum[lca(x,y)]-=2; #include<bits/stdc++.h> using namespace std; #define int long long const int N=5e5+10;
树上启发式合并 作用 主要解决树上对每个根节点的影响,复杂度最好O(nlog n),最差O(N*N) #include <bits/stdc++.h> using namespace std; #define ll long long const ll N = 1e5 + 10; ll dep[N], sze[N], son[N]; ll dian[N]; ll lev[N]; ll max_len; ll ans[N]; ll flag; ll
我没有话说 Code: #include<bits/stdc++.h> using namespace std; char buf[1<<20],*p1,*p2; #define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++) //#define GC getchar() template<class T> inline void read(T &n
前置知识 首先回忆以下差分数组: \(b[1]=a[1]\) \(b[i]=a[i]-a[i-1](2\leq i\leq n)\) 如果要在\(l,r\)区间\(+k\),就在\(l\)加\(k\) 在\(r+1\)处\(-k\) 点的差分 如果我们要点\(u,v\)之间的路径加上某一个数\(d\),直接\(dfs\)的话,肯定会\(T\)飞,这时我们就可以用树上差分来作,类比一下
笛卡尔树本质是一种 \(treap\),可以线性构建,在构造数据下并不平衡 对于一个排列,其笛卡尔树 \(dfs\) 序为下标,其权值满足小(大)根性质 笛卡尔树可以很好地把序列问题转化为树上问题,其好处在于很方便地利用树上左右子树大小进行处理 笛卡尔树与数列的对应关系: 区间 \(RMQ\) 对应笛卡尔
https://www.luogu.com.cn/problem/U182917 #include <bits/stdc++.h> using namespace std; const int N = 3000010; bool vis[N]; int to[N]; int nxt[N]; int head[N]; int E; void init() { E = 0; memset(head, -1, sizeof head); } void add_edge(int a, in