lca

图论小专题B

谁都会走 提交于 2019-11-26 14:57:41
2 树 2.1 树的定义 一个只有 \(N-1\) 条边,且任意两个点连通的图叫做树。通过这样定义的树往往是一棵无根树,而我们通常会任意选定一个根节点使其变成有根树。有根树可以定义“父亲和儿子”的层次关系,这往往有利于构造最优子结构,进行DP和搜索等操作。 特别的,如果在树上任意加上一条边,那么整个树上就会多出一个环。我们称这样的树是“基环树”。基环树不是树,但是它只有一个环。将整个环作为一个“广义根”,然后将根和连在环上的子树分开处理,同样可以套用树的许多算法。 2.2 树上的DP算法 通常选定一个根,然后用DFS计算。至于递归接口应该放在转移之前还是之后呢?那就看方程怎么写了。在写程序的时候,只要满足“已知推未知”的原则就行。 如果给定一棵无根树,答案要求给出最优的根使得某个值最优化,这时可以采用“换根法”。先任意选定一个根计算出规划值 \(F_1\) ,然后从数学上推导出以任意点为根的规划值 \(F_2\) 。《进阶指南》上有相关的例题。 2.2.1 树的参量 子树大小size 最基础的量。转移方程简记为 \(F(x)=1+\sum F(\text{son}(x))\) 树的重心 和size一样。如果子树 \(x\) 的大小是 \(\text{size}(x)\) ,那么剩下树的大小就是 \(N-\text{size}(x)\) 。在求 \(\text{size}\)

NKOJ P3815 树上的询问 (LCA 倍增)

喜夏-厌秋 提交于 2019-11-26 14:51:48
评测说明 : 1000ms 问题描述 现有一棵 n 个节点的树,树上每条边的长度均为 1。给出 m 个询问,每次询问两个节 点 x,y,求树上到 x,y 两个点距离相同的节点数量。 输入格式 第一个整数 n,表示树有 n 个点。 接下来 n-1 行每行两整数 a,b,表示从 a 到 b 有一条边。 接下来一行一个整数 m,表示有 m 个询问。 接下来 m 行每行两整数 x,y,询问到 x 和 y 距离相同的点的数量。 输出格式 共 m 行,每行一个整数表示询问的答案。 样例输入 7 1 2 1 3 2 4 2 5 3 6 3 7 3 1 2 4 5 2 3 思路: 被坑了好久 一直没调出来 复习了一波LCA 后 终于A 了 注意 倍增的用法 即GOUP 操作 顺便复习一下 距离倍增 code: g[x][i]=g[x][i-1]+g[fa[x][i-1]][i-1]; dis 求法 for(i=0;i<=ss;i++) if(k&(1<<i))dis+=g[x][i],x=fa[x][i]; if(x==y)return dis; for(i=s;i>=0;i--) if(fa[x][i]!=fa[y][i]) { dis+=g[x][i];x=fa[x][i]; dis+=g[y][i];y=fa[y][i]; } return dis+=g[x][0]+g[y][0];

Tarjan算法(lca)

隐身守侯 提交于 2019-11-26 14:31:04
http://codevs.cn/problem/2370 / 2370 小机房的树 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上。有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力。已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计一个程序来找到这条路,要求你告诉他们最少需要花费多少精力 输入描述 Input Description 第一行一个n,接下来n-1行每一行有三个整数u,v, c 。表示节点 u 爬到节点 v 需要花费 c 的精力。第n+1行有一个整数m表示有m次询问。接下来m行每一行有两个整数 u ,v 表示两只虫子所在的节点 输出描述 Output Description 一共有m行,每一行一个整数,表示对于该次询问所得出的最短距离。 样例输入 Sample Input 3 1 0 1 2 0 1 3 1 0 2 0 1 2 样例输出 Sample Output 1 1 2 数据范围及提示 Data Size & Hint 1<=n<=50000, 1<

LCA

自古美人都是妖i 提交于 2019-11-26 14:20:52
倍增算法: 每个数都可以用二进制表示,2^30是一个很大的数,所以可以从二进制的第三十位开始,往后找,可以根据条件找到最大最合适的数。 例题: C - Closest Common Ancestors Write a program that takes as input a rooted tree and a list of pairs of vertices. For each pair (u,v) the program determines the closest common ancestor of u and v in the tree. The closest common ancestor of two nodes u and v is the node w that is an ancestor of both u and v and has the greatest depth in the tree. A node can be its own ancestor (for example in Figure 1 the ancestors of node 2 are 2 and 5) The data set starts with the tree description, in the form: nr_of_vertices vertex:(nr_of

BSOJ 4490 避难向导

谁说我不能喝 提交于 2019-11-26 14:15:31
题目大意:树上的每一个节点都有一个d[i],定义为离最远节点的距离,还有一个s[i]=(d[i]+a)×b%c,再m次询问,每次询问给定(x,y,q),要求求出(x,y)路径上距x最近的一个点,且满足当前点的s[i]≥q。 emm...这一看就是两道题强行拼起来的,先求出s[i],然后在处理路径上的询问。 显然对于任意点,距离它最远的点一定是直径的两个端点之一,可以用两次DFS把直径的两端求出来,再把两个距离取个max就行了,算完d[i]后就可以算出s[i]啦。 一看到路径上的询问,我就想起了树剖,但冷静后再想想,这是一道静态问题!直接树上倍增乱搞就行了。 我的思路是这样的: p[i][j]表示i的第2 k 个祖先,g[i][j]表示i到它的第2 k 个祖先中s[i]的最大值(不包含i本身) 对于任意一条路径,都可以从LCA(x,y)中拆开(如图) 分为两段(x,LCA(x,y)),(LCA(x,y),y)讨论 在(x,LCA(x,y))上时,设Ask(x,k,q)为x到2 k 祖先中第一个s[i]≥q的i(不含x),通过二分的思想: Ask(x,k,q)=-1 (g[i][k]<q) Ask(x,k,q)=p[x][0] (g[i][0]≥q && k=0) Ask(x,k,q)=Ask(x,k-1,q) Ask(x,k,q)=Ask(p[x][k-1],k-1,q) (Ask

LCA Nearest Common Ancestors (很典型的例题)

蓝咒 提交于 2019-11-26 14:05:52
A rooted tree is a well-known data structure in computer science and engineering. An example is shown below: In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree. Node x is an ancestor of node y if node x is in the path between the root and node y. For example, node 4 is an ancestor of node 16. Node 10 is also an ancestor of node 16. As a matter of fact, nodes 8, 4, 10, and 16 are the ancestors of node 16. Remember that a node is an ancestor of itself. Nodes 8, 4, 6, and 7 are the ancestors of node 7. A node x is called a common ancestor of two

P1600 天天爱跑步

廉价感情. 提交于 2019-11-26 12:45:54
传送门 考虑一个玩家的路径 $(x,y)$ 对路径上的一个节点 $u$ 的贡献 设 $lca=LCA(x,y)$ ,当 $u$ 在链 $x,lca$ 上时,路径会产生 $1$ 的贡献当且仅当 $dep[x]-dep[u]=w[u]$ 其中 $dep[i]$ 表示节点 $i$ 的深度,$w[i]$ 就是题目给出的 $W$,上式即 $dep[x]=dep[u]+w[u]$ 当 $u$ 在链 $lca,y$ 上时,路径会产生贡献当且仅当 $dep[y]-dep[u]=dis(x,y)-w[u]$ 其中 $dis(x,y)$ 表示节点 $x,y$ 的路径长度,上式即 $dep[y]-dep[u]=dep[x]+dep[y]-2dep[lca]-w[u]$ 即 $-dep[x]+2dep[lca]=dep[u]-w[u]$ 直接树链剖分并对每种深度维护动态开点线段树,分别维护上面两种情况,对于一条路径 $(x,y)$ 直接把对应深度的线段树的, $x$ 到 $y$ 的所有节点$+1$ 即深度为 $dep[x]$ 和深度为 $-dep[x]+2dep[lca]$ ,注意这是两种情况,对每种深度都要两颗线段树分别维护 因为有第二种情况的深度可能有负数,所以要把深度加 $N$ 转成正的,变成 $2dep[lca]-dep[x]+N$,并 注意这样搞 $lca$ 会被算两次,要减一次 查询节点 $u

树链剖分 树剖求lca 学习笔记

谁都会走 提交于 2019-11-26 12:45:46
树链剖分 顾名思义,就是把一课时分成若干条链,使得它可以用数据结构(例如线段树)来维护 一些定义: 重儿子:子树最大的儿子 轻儿子:除了重儿子以外的儿子 重边:父节点与重儿子组成的边 轻边:除重边以外的边 重链:重边连接而成的链 轻链:轻边连接而成的链 链头:一条链上深度最小的点 第一步:进行进行轻重边的划分。 定义size[x]为以x为根的子树节点个数,令v为u儿子中size值对打的节点,那么(u,v)就是重边,其它出边都是轻边 两个重要性质: 1.轻边(u,v)中,Size[v]<size[u]/2 显然,如果儿子v的size>=size[u],则它应该是重边,u的子树中没有size比他更大的 (作者考试爆零去了,一会再写) 来源: https://www.cnblogs.com/lzy-blog/p/11320613.html

LCA最近公共祖先---倍增法笔记

最后都变了- 提交于 2019-11-26 12:29:12
先展示把代码发过来,今日有空再更新 #pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; const int N = 1000000; long long bit[N]; int depth[N],f[N][30]; vector<int> G[N]; void init(){ //预先把2的多少次方计算出来 bit[0]=1; for(int i=1;i<=29;i++) bit[i]=bit[i-1]*2; } void dfs(int u,int par){ //u:当前节点 par:u的父亲节点 depth[u]=depth[par]+1; f[u][0]=par; for(int i=1;i<=29;i++) f[u][i]=f[f[u][i-1]][i-1]; //计算u的各次方的祖先 for(int i=0;i<(int)G[u].size();i++){ //继续去遍历该节点的孩子节点 int v=G[u][i]; if(v==par) continue;//因为是用邻接表存的,所以需要跳过父亲节点 dfs(v,u); } } int lca(int a,int b){ if(depth[a]<depth[b]) swap(a,b); //保证深度大的在前,小的在后 int dif