lca

「SDOI2013」森林

随声附和 提交于 2020-01-24 00:07:22
「SDOI2013」森林 传送门 树上主席树 + 启发式合并 锻炼码力,没什么好说的。 细节见代码。 参考代码: #include <algorithm> #include <cstdio> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout) using std ::sort; using std ::swap; using std ::unique; using std ::lower_bound; inline char _getchar() { static char buf[100000], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++; } template < class T > inline void read(T& s) { s = 0; rg int f = 0; rg char c = _getchar(); while ('0' > c || c > '9') f |= c == '-', c = _getchar(); while ('0' <

「luogu2633」Count on a tree

与世无争的帅哥 提交于 2020-01-23 23:42:42
「luogu2633」Count on a tree 传送门 树上主席树板子。 每个节点的根从其父节点更新得到,查询的时候差分一下就好了。 参考代码: #include <algorithm> #include <cstdio> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout) using namespace std; template < class T > inline void read(T& s) { s = 0; int f = 0; char c = getchar(); while ('0' > c || c > '9') f |= c == '-', c = getchar(); while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar(); s = f ? -s : s; } const int _ = 1e5 + 5; int tot, head[_], nxt[_ << 1], ver[_ << 1]; inline void Add_edge(int u, int v) { nxt[++tot] = head[u], head[u] = tot, ver

LCA

微笑、不失礼 提交于 2020-01-22 20:28:16
\(LCA\) ,即最近公共祖先,是指在有根树中,找出某两个结点 \(u\) 和 \(v\) 最近的公共祖先 倍增法求 \(LCA\) ,核心本质是让两个结点每次向上走2的幂次步 先处理出倍增数组 \(fa\) , \(fa[i][j]\) 为从结点 \(i\) 向上走 \(2^{j}\) 步后能走到的结点 再将两个点移到同一深度 最后开始倍增来跳深度,应用了二进制拆分思想 时间复杂度为 \(O(n\ log\ n)\) \(code\) : void dfs(int x,int fath) { de[x]=de[fath]+1;//求深度 fa[x][0]=fath; for(int i=1;(1<<i)<=de[x];++i) fa[x][i]=fa[fa[x][i-1]][i-1];//初始化倍增 for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(y==fath) continue; dfs(y,x); } return; } int lca(int x,int y) { if(de[x]<de[y]) swap(x,y); for(int i=20;~i;--i) if(de[fa[x][i]]>=de[y]) x=fa[x][i]; if(x==y) return x; for(int i=20;~i;--i) {

最近公共祖先:LCA及其用倍增实现 +POJ1986

空扰寡人 提交于 2020-01-22 11:04:23
Q : 为什么我在有些地方看到的是最小公共祖先? A :最小公共祖先是LCA(Least Common Ancestor)的英文直译,最小公共祖先与最近公共祖先只是叫法不同。 Q : 什么是最近公共祖先(LCA)? A :最近公共祖先的概念是很好理解的。首先,你需要脑补出一棵树(它可以是二叉树,也可以是多叉树。)之后,请你再在你脑补出的树上任取两个点。每个点都可以到达树根,且到达的路径是唯一的,既然两个点都可以到达树根,那么根无疑是这两个点的公共祖先。然而,根却不一定是这两个点的最近公共祖先,相反,离根距离最远且在两条点到根路径上的点才是最近公共祖先(最近公共父节点)。 实现求LCA的方法有很多种,无论是离线还是在线,是TARJAN还是RMQ等等都可以实现。在此,安利一种PO主钟爱的方法:倍增,来实现LCA。 首先,你不可以认为倍增实现LCA和RMQ实现LCA是指的同一回事情,哪怕RMQ的完成是用了倍增思想。事实上,RMQ实现LCA的程序比较繁琐,并且需要你考虑到众多细节。而这些细节的调试在比赛有限的时间内无疑是要爆炸的。比如说,PO主就在某次D2T3跪在了RMQ实现LCA上QWQ。与RMQ相反,倍增实现的代码要比RMQ实现简单一些,并且好脑补,而且容易调试,相信大家一定可以弄明白倍增实现LCA的QWQ 在没有学习倍增写LCA之前,你是怎么样求LCA的呢?至少

1151 LCA in a Binary Tree (30分)

守給你的承諾、 提交于 2020-01-22 05:19:07
The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U and V as descendants. Given any two nodes in a binary tree, you are supposed to find their LCA. Input Specification: Each input file contains one test case. For each case, the first line gives two positive integers: M (≤ 1,000), the number of pairs of nodes to be tested; and N (≤ 10,000), the number of keys in the binary tree, respectively. In each of the following two lines, N distinct integers are given as the inorder and preorder traversal sequences of the binary tree, respectively. It is

st表、RMQ和LCA

无人久伴 提交于 2020-01-20 20:23:59
int lca(int x,int y) { if(de[x]<de[y]) swap(x,y); int d=de[x]-de[y]; for(int i=log2(d);i>=0;i--) { if(d&(l<<i)) { x=fa[x][i]; } } for(int i=log2(n);i>=0;i--) { if(fa[x][i]!=fa[y][i]) { x=fa[x][i]; y=fa[y][i]; } } if(x!=y) { return fa[x][0]; } else { return x; } } 来源: https://www.cnblogs.com/liusu123456/p/12219221.html

Tarjan算法求LCA

走远了吗. 提交于 2020-01-19 16:01:14
题源: https://loj.ac/problem/10130 这个题还是debug了好久。。 1.调用函数中如果要更改外部数据需要传递引用,其实传递引用往往效率更高,以后要多加注意这一点。 2.忘写并查集了 (捂脸逃) 3.题目要求的是距离而不是lca,认真审题。。 贴代码: #include <iostream> #include <stdio.h> #include <cstring> #define maxn 100005 //#define LOCAL using namespace std; struct Edge { int next, to, dis; } edge[maxn * 2], queryEdge[maxn * 2]; //两倍存储(不知道父子关系与遍历的先后顺序) int head[maxn], queryHead[maxn], e1 = -1, e2 = -1, fa[maxn], vs[maxn], dep[maxn]; //dep用来记录深度求距离 void addedge(int *head, Edge *edge, int &e, int x, int y) //e要传递引用来进行更改,否则++无效 { edge[++e].next = head[x], edge[e].to = y, head[x] = e; edge[++e].next

1759:采访计划

江枫思渺然 提交于 2020-01-18 00:11:38
时间限制: 2000 ms 内存限制: 131072 KB 【题目描述】 公元2044年,人类将进入宇宙纪元。L国有n个星球,分别编号为1到n,每一星球上有一个球长。 因为历史的长期积淀,第i个星球上还有一位编号为i的德高望重的长者,因为长者德高望重,所以第i个星球的球长一定被第i位长者管辖且长者管辖自己。 每一位长者手里有一份名单Bi,上面记录着一些长者的编号。 因为一些奥妙重重的原因,第i位长者的名单上只可能有1至i-1中的一些编号并且保证不会重复。 因为长者都德高望重,所以第i位长者管辖第j位长者的充要条件是:对于每一个k属于Bi,第k位长者管辖第j位长者。 此时,有一位记者想对一些球长进行采访,为了保证采访顺利,他决定先与一些长者搞好关系,以便采访被这些长者管辖的球长。 为了与更多的球长谈笑风生,这位记者会给你提出m个询问。 第i个询问中记者会给你fi个长者的编号,你需要回答有多少个星球的球长至少直接或间接被一位长者管辖。m≤2000000 。 【输入】 第一行一个数n,表示星球的个数。 接下来n行,每一行描述一个Bi:首先给出Bi的大小szi(可能为0),接下来szi个数,描述Bi中的每一个元素。保证Bi中的数没有重复。 接下来一行,给出一个数m,表示询问的个数。 接下来m行,每一行描述一个询问:格式同上文对于集合Bi的格式。 【输出】 共m行,第i行输出第i次询问的答案

RMQ求LCA

雨燕双飞 提交于 2020-01-16 20:31:13
题目链接 rmq求LCA,interesting。 一直没有学这玩意儿是因为CTSC的Day1T2,当时我打的树剖LCA 65分, gxb 打的rmq LCA 45分。。。 不过rmq理论复杂度还是小一点的,就学一下把。 RMQ求LCA 我们要用到三个数组 \(dfn[i]\) :第 \(i\) 个节点位置的时间戳 \(id[i][j]\) :在欧拉序中 \(i\) 到 \(i + 2^j - 1\) 这段区间内深度最小的节点编号 \(dep[i]\) :第 \(i\) 个节点的深度 实际上用到了一个性质: 对于任意两点的 \(LCA\) ,一定是它们欧拉序中两点之间的最小值 欧拉序是什么?就是把dfs中遍历到每一个一个节点(包括回溯时遍历到)加到一个序列里,最终得到的就是欧拉序 时空复杂度 设 \(T = 2 * n - 1\) 时间复杂度: 预处理: \(O(TlogT)\) 查询: \(O(1)\) 空间复杂度: 考虑欧拉序中有多少个点,首先每个点被访问到的时候会做出 \(1\) 的贡献 其次在遍历每条边时会多出 \(1\) 的共贡献 因此总空间复杂度为: \(O(T)\) // luogu-judger-enable-o2 #include<bits/stdc++.h> const int MAXN = 1e6 + 10; using namespace std;

Luogu5327 ZJOI2019语言(树上差分+线段树合并)

China☆狼群 提交于 2020-01-14 14:34:19
  暴力树剖做法显然,即使做到两个log也不那么优美。   考虑避免树剖做到一个log。那么容易想到树上差分,也即要对每个点统计所有经过他的路径产生的总贡献(显然就是所有这些路径端点所构成的斯坦纳树大小),并支持在一个log内插入删除合并。   考虑怎么求树上一些点所构成的斯坦纳树大小。由虚树的构造过程容易联想到,这就是按dfs序排序后这些点的深度之和-相邻点的lca的深度之和(首尾视作相邻),也就相当于按dfs序遍历所有要经过的点并回到原点的路径长度/2。   这个东西显然(应该)可以set启发式合并维护,但同样就变成了两个log。可以改为线段树合并,线段树上每个节点维护该dfs序区间内dfs序最小和最大的被选中节点,合并时减去跨过两区间的一对相邻点的lca的深度即可。这需要计算O(nlogn)次lca,使用欧拉序rmq做到O(1)lca查询就能以总复杂度O(nlogn)完成。 #include<bits/stdc++.h> using namespace std; #define ll long long #define N 100010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n