lca

BZOJ4668: 冷战 (并查集 + LCA)

倖福魔咒の 提交于 2019-11-29 18:51:53
题意:动态给点连边 询问两个点之间最早是在第几个操作连起来的 题解:因为并查集按秩合并 秩最高是logn的 所以我们可以考虑把秩看作深度 跑LCA #include <bits/stdc++.h> using namespace std; const int MAXN = 5e5 + 5; int n, m, cnt; int fa[MAXN]; int id[MAXN]; int zhi[MAXN]; int find(int x) { if(fa[x]) return find(fa[x]); else return x; } int ffind(int x) { if(fa[x]) return ffind(fa[x]) + 1; else return 0; } void add(int x, int y, int z) { int fx = find(x); int fy = find(y); if(fx != fy) { if(zhi[fx] < zhi[fy]) { fa[fx] = fy; id[fx] = z; } else fa[fy] = fx, id[fy] = z; if(zhi[fx] == zhi[fy]) zhi[fx]++; } } int query(int x, int y) { int fx = find(x); int fy = find

洛谷 P3398 仓鼠找sugar 题解

て烟熏妆下的殇ゞ 提交于 2019-11-29 17:16:58
先说一下题意: 在一颗树上一个仓鼠从a走到b,一个他的基友从c走到d求他两个是不是会有相遇的地方。 一道求lca的题目。 这道题只看题目是很难找出规律的,但是一画图他的规律就很显然了 可以发现如果两条路径如果相交那一对点的最近公共祖先一定在另一台的路径上 不然如果相交那就这能两条边交叉,这在树中是不可能出现的 否则就不是一棵树 但是怎么确定这到底是不是回相遇的呢? 可以先求出仓鼠目的地b和出发点a的最近公共祖先qwq和surger的 目的地d和出发点c的最近公共祖先awa 然后分别求出a和d,a和c,b和d,b和c的最近公共祖先来和 前面求出的两个最近公共祖先的深度比较如果有一个这两个 深度小那就是不可行的不然如果都比他深度深或者等于的话 那就是可能遇见的 但是怎么证明只要他们的最近公共祖先的深度大于等于awa和qwq 那就是可行的呢? 这个在三克油大佬的博客里面已经证明的很好啦,我就不多说了 附上链接 这里 #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int Max = 100005; struct node { int y,ne; }a[Max << 1]; int head[Max]; int f[Max][22]; int tot = 0; void

Luogu P3833 [SHOI2012]魔法树

北战南征 提交于 2019-11-29 16:14:00
此题理论最优解 题目链接 题目大意:路径修改,子树求和 明显是树剖的模板,但树剖的时间复杂度 高 达了优秀的$\Theta(Q \;log^2n)$,而实际上树上差分可以把时间复杂度降到$\Theta(Q \;logn)$。 设$tag[x]$为$1$到$x$的路径上全都加了这个值, 显然 对于$(x,y)$这条路径加$d$的操作可以看作 $$tag[x]+=d,tag[y]+=d,tag[LCA(x,y)]-=d,tag[prt[LCA(x,y)]]-=d$$ 若查询以$root$为根的子树和,考虑子树内每个点$x$对答案的贡献是 $$(dep[x]-dep[root]+1)\times tag[x]$$ 上式的意义是在$(x,root)$这条路径每个点都被加了$tag[x]$,对上式求和得到 $$\sum \;((dep[x]-dep[root]+1)\times tag[x])$$ $$\sum \;(dep[x]\times tag[x]-(dep[root]-1)\times tag[x])$$ $$\sum \;(dep[x]\times tag[x])-(dep[root]-1)\times\sum\;(tag[x])$$ 两个树状数组维护$dep[x]\times tag[x]$和$tag[x]$就好了,因为在$DFS$序上子树是连续的区间,直接查询即可。

「LCA」[USACO10HOL]牛的政治Cow Politics

自作多情 提交于 2019-11-29 11:16:35
[USACO10HOL]牛的政治Cow Politics 题目链接: [USACO10HOL]牛的政治Cow Politics 题目大意 给你 \(n\) 个关系,再给你一共有多少个群落,每个关系包含两个内容,在哪个群落以及当前 \(i\) 节点的父亲节点是谁。然后让你求每个群落距离最远的两个点的距离是多大 题目题解 刚开始想的是树的直径,但看了下样例发现都是在一棵树上进行的,搜肯定不怎么好搜,想想其他的办法。然后又想到LCA可以求两点的距离,那么可以考虑用LCA求两点距离,这里我们通过题意理解可以知道,如果选择一个深度最深的点作为其中一个点,那么其定会有一种与其他点的距离方案是我们的答案(简单的贪心),那么我们先确定一点的位置,然后再通过遍历和计算直接计算最大的距离不就OK了吗,然后就... AC了 代码如下 //#define fre yes #include <cstdio> #include <cstring> #include <iostream> const int N = 200005; int head[N << 1], to[N << 1], ver[N << 1]; int maxx[N], color[N], ans[N]; int depth[N], f[N][22], lg[N]; int n, m, root; int tot; void addedge

洛谷P3128 最大流Max Flow 树上差分

梦想的初衷 提交于 2019-11-29 00:49:33
给定一个 n ≤ 5 e 4 n\leq5e4 n ≤ 5 e 4 的树,已经 m ≤ 1 e 5 m\leq1e5 m ≤ 1 e 5 次操作,每次操作会选择两个点 u u u 和 v v v ,使得两点路径上所有的点都加 1 1 1 ,求点权的最大值。 直接暴力是 O ( n m ) O(nm) O ( n m ) 的,这里考虑差分最后再求前缀和。树上的差分分为点差分和边差分,这里是点差分。对 u , v u,v u , v 分别 + 1 +1 + 1 ,然后对 l c a ( u , v ) lca(u,v) l c a ( u , v ) 和 f a ( l c a ( u , v ) ) fa(lca(u,v)) f a ( l c a ( u , v ) ) 分别 − 1 -1 − 1 ,最后一遍 d f s dfs d f s 处理即可。 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const ll INF=LONG_LONG_MAX; const int N=5e4+7; vector<int> G[N]; int fa[N][18],dep[N]; int cnt[N]; void dfs1(int u,int f) {

CD操作 HDU - 4547(裸LCA)

荒凉一梦 提交于 2019-11-28 20:17:33
CD操作 HDU - 4547(裸LCA) 题目: 传送门 思路见注释 代码 : # include <bits/stdc++.h> # define mset(a,b) memset(a,b,sizeof(a)) using namespace std ; typedef long long ll ; typedef pair < int , int > P ; const int inf = 0x3f3f3f3f ; const int N = 1e5 + 10 ; const int DEG = 20 ; vector < int > g [ N ] ; int fa [ N ] [ DEG + 1 ] , deg [ N ] , du [ N ] ; unordered_map < string , int > mmp ; int tol ; int getid ( string s ) { if ( mmp [ s ] == 0 ) { mmp [ s ] = ++ tol ; return tol ; } return mmp [ s ] ; } void bfs ( int root ) { queue < int > Q ; Q . push ( root ) ; fa [ root ] [ 0 ] = root ; deg [ root ] = 0 ; while

BZOJ1146: [CTSC2008]网络管理Network

走远了吗. 提交于 2019-11-28 19:02:49
题意 树链上带修改第K大 思路 树链剖分+线段树套平衡树+二分 具体就是先树剖把树映射到区间,然后对区间建线段树,线段树的每一个节点是一颗权值平衡树,修改就是在线段树上跑一遍,对于经过的线段树节点,其实就是平衡树,做一次删除和一次添加。查询就是二分最终的答案ans,然后计算链上大于ans的节点有多少,这一计算只需要在线段树上跑一遍,对于经过的线段树节点计算对应的平衡树里有多少大于ans的节点再加起来就可以了。 二分一个 \(logn\) ,跑树链一个 \(logn\) ,跑线段树一个 \(logn\) ,查询平衡树一个 \(logn\) ,一共 \(O(mlog^4n)\) 。我的代码跑了将近46s 树链剖分+树状数组套主席树 类似query on a tree,借助lca的性质来维护树链信息,然后由于带修改,所以在外套一个树状数组来处理修改。每次询问需要对 \(logn\) 颗主席树进行修改,一次修改 \(logn\) ,一共 \(O(mlog^2n)\) 。 WA到自闭,对着空气改了半天,最后发现是数组开小了 跑了大概8s 整体二分 留个坑 不会整体二分 AC代码:思路一 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=4e5+5; const int INF

倍增求LCA

牧云@^-^@ 提交于 2019-11-28 13:14:55
倍增求LCA 一,首先回顾一下什么是倍增算法,倍增算法就是改善一下一步一步跳的缓慢,改为跳2^k 步从而达到加快速度的目的,倍增算法一般要先预处理一个数组,代表从从某个点开始跳2^k 个数到达哪里,比如ST表的ST[i][j]代表从第i个数向后2^j 个数,树上倍增求LCA的f[i][j]表示i的第2^j 个祖先是谁。 二,最近公共祖先LCA概念篇 1,祖先:与x处于同一条重链且深度小于点x的节点都成为点想的祖先。 2,公共祖先:若给定一棵树,结点z即是结点x的祖先,结点z也是结点y的祖先,那么称z是结点x和y的公共祖先。 3,最近公共祖先:结点x和结点y的所有祖先中深度最深的那个,记作LCA(x,y)。 比如在此图中,5的祖先有1和2; 5和6的公共祖先有1和2; 5和6的最近公共祖先是2; 有没有发现根节点是所有任意两个节点的公共祖先, 所以最近公共祖先一定存在,最差是根节点。 三,如何求解LCA 1,考虑如何暴力求解,如果两个结点的深度相同,我们是不是只需要让两个结点同时一步一步往上走,即a走到它的父亲的同时,b也走到它的父亲,如果两个点走到的结点不相同就证明当前节点不是a和b的最近公共祖先就继续走,知道走到节点相同证明当前节点是点a和点b的最近公共祖先。 2,考虑如何优化1,1缓慢的原因是它在一步一步的向上走所以导致了算法的低效,如果我们可以大步向上走

ZJOI2016 大森林

左心房为你撑大大i 提交于 2019-11-28 12:52:58
大森林 小Y家里有一个大森林,里面有 \(n\) 棵树,编号从 \(1\) 到 \(n\) 。一开始这些树都只是树苗,只有一个节点,标号为 \(1\) 。这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力。小Y掌握了一种魔法,能让第 \(l\) 棵树到第 \(r\) 棵树的生长节点长出一个子节点。同时她还能修改第 \(l\) 棵树到第 \(r\) 棵树的生长节点。她告诉了你她使用魔法的记录,你能不能管理她家的森林,并且回答她的询问呢? Input 第一行包含 \(2\) 个正整数 \(n,m\) ,共有 \(n\) 棵树和 \(m\) 个操作。接下来 \(m\) 行,每行包含若干非负整数表示一个操作,操作格式为: 0 l r 表示将第 \(l\) 棵树到第 \(r\) 棵树的生长节点下面长出一个子节点,子节点的标号为上一个 \(0\) 号操作叶子标号加 \(1\) (例如,第一个 \(0\) 号操作产生的子节点标号为 \(2\) ), \(l\) 到 \(r\) 之间的树长出的节点标号都相同。保证 \(1≤l≤r≤n\) 。 1 l r x 表示将第 \(l\) 棵树到第 \(r\) 棵树的生长节点改到标号为 \(x\) 的节点。对于 \(i (l≤i≤r)\) 这棵树,如果标号 \(x\) 的点不在其中,那么这个操作对该树不产生影响。保证 \(1≤l≤r

LCA

五迷三道 提交于 2019-11-28 12:27:28
A - How far away ? HDU - 2586 LCA倍增 #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<stack> #include<cstdlib> #include<queue> #include<set> #include<string.h> #include<vector> #include<deque> #include<map> using namespace std; #define INF 0x3f3f3f3f3f3f3f3f #define inf 0x3f3f3f3f #define eps 1e-4 #define bug printf("*********\n") #define debug(x) cout<<#x"=["<<x<<"]" <<endl typedef long long LL; typedef long long ll; const int maxn = 4e4 + 5; const int mod = 998244353; int cnt,DEG = 30; int vis[maxn],head[maxn],dep[maxn],fa[maxn][30],dis[maxn];