lca

树链剖分【洛谷P4114】 Qtree1

…衆ロ難τιáo~ 提交于 2020-03-15 11:30:50
P4114 Qtree1 题目描述 给定一棵n个节点的树,有两个操作: CHANGE i ti 把第i条边的边权变成ti QUERY a b 输出从a到b的路径中最大的边权,当a=b的时候,输出0 码农题。 话说我码得变快了啊,虽然跟顾z吹45分钟码完Qtree没有完成,不过总共用了55分钟还是不长的嘿嘿。 code: #include <iostream> #include <cstdio> #define ls(o) o<<1 #define rs(o) o<<1|1 #define int long long using namespace std; const int wx=500017; int head[wx],dfn[wx],size[wx],f[wx][23],dis[wx][23],dep[wx]; int son[wx],a[wx],top[wx],tid[wx]; int n,num,tot; char opt[17]; inline int read(){ int sum=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar(

tarjan算法求LCA

这一生的挚爱 提交于 2020-03-15 06:46:07
tarjan算法求LCA LCA(Least Common Ancestors)的意思是最近公共祖先,即在一棵树中,找出两节点最近的公共祖先。 这里我们使用tarjan算法离线算法解决这个问题。 离线算法,是指首先读入所有的询问(求一次LCA叫做一次询问),然后重新组织查询处理顺序以便得到更高效的处理方法。Tarjan算法是一个常见的用于解决LCA问题的离线算法,它结合了深度优先遍历和并查集,整个算法为线性处理时间。 总思路就是每进入一个节点u的深搜,就把整个树的一部分看作以节点u为根节点的小树,再搜索其他的节点。每搜索完一个点后,如果该点和另一个已搜索完点为需要查询LCA的点,则这两点的LCA为另一个点的现在的祖先。 1.先建立两个链表,一个为树的各条边,另一个是需要查询最近公共祖先的两节点。 2.建好后,从根节点开始进行一遍深搜。 3.先把该节点u的father设为他自己(也就是只看大树的一部分,把那一部分看作是一棵树),搜索与此节点相连的所有点v,如果点v没被搜索过,则进入点v的深搜,深搜完后把点v的father设为点u。 4.深搜完一点u后,开始判断节点u与另一节点v是否满足求LCA的条件,满足则将结果存入数组中。 5.搜索完所有点,自动退出初始的第一个深搜,输出结果。 如上图,根据实现算法可以看出,只有当某一棵子树全部遍历处理完成后,才将该子树的根节点标记为有颜色

lca 倍增模板

混江龙づ霸主 提交于 2020-03-13 12:29:13
https://www.cnblogs.com/lbssxz/p/11114819.html 1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 const int maxn=1e5+10; 5 int n,m,s,num=0,head[maxn],dep[maxn],f[maxn][23]; 6 int a1,a2; 7 struct edg{ 8 int next,to; 9 }G[maxn]; 10 void edge_add(int u,int v)//链式前向星存图 11 { 12 num++; 13 G[num].next=head[u];G[num].to=v;head[u]=num; 14 G[++num].next=head[v];G[num].to=u;head[v]=num; 15 } 16 void dfs(int u,int father)//对应深搜预处理f数组 17 { 18 dep[u]=dep[father]+1; 19 for(int i=1;(1<<i)<=dep[u];i++){ 20 f[u][i]=f[f[u][i-1]][i-1]; 21 } 22 for(int i=head[u];i;i=G[i].next){ 23 int v=G[i].to; 24

HDU 4912 Paths on the tree

点点圈 提交于 2020-03-06 13:59:12
题意 树上有一堆路径,问最多选择多少条路径使得每个点最多被一条路径覆盖 我们先把每条路径 \(u,v\) 的 lca 求出来记为 \(lca_{u,v}\) , 然后我们来想一想,对于一个节点来说,选择怎样的一条路径才能让这条路径尽量不影响其他路径 我们就可以选择任意一条 lca位于这个点的路径,因为这样这条路径就不会影响到子树外的那些了,然后我们可以按照 lca 从深到浅的顺序来模拟,这样就一定保证是最优的,因为路径无权,一个点又只能被覆盖一次 // This code writed by chtholly_micromaker(MicroMaker) #include <bits/stdc++.h> #define reg register #define int long long using namespace std; const int MaxN=100050; struct Edge { int nxt,to; }E[MaxN<<2]; struct Node { int a,b; int lca; }a[MaxN]; template <class t> inline void rd(t &s) { s=0; reg char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) s=(s<<3

C++最近公共祖先(LCA版)

百般思念 提交于 2020-03-05 20:34:05
C++最近公共祖先(LCA版) 问题描述 给出一棵有N(编号1到N)个节点的有根树,求出指定节点对的最近公共祖先! 对于树中节点x而言,从根节点到达x的这一条路径中经过的所有节点,都称为x的祖先。 如上图所表示的树中, 根节点为8。8、4、10、16都是12的祖先。对于6和12这对节点而言,从6出发往上朝根走和从12出发往上朝根走的两条路径最早交汇的地点是4号节点,因此4号点是6和12的最近公共祖先。 同理,11和9的最近公共祖先是8; 10和3的最近公共祖先是10;2和7的最近公共祖先是4… 输入格式 第一行,一个整数N。表示树中节点总数 接下来N-1行,每行两个整数x和y,表示x是y的父亲。 接下来一行,一个整数M,表示询问的总数 接下来M行,每行两个整数a和b,表示询问a和b的最近公共祖先。 输出格式 M行,每行一个整数,表示对应询问的答案。 大概思路: 用dep[]来标记树的深度,fa[v][k]来标记v点向上2^k 步骤:1.DFS来确定层数,将x,y移到同一水平线; 2.将x,y同时向上移,如果x==y就return x; 不说了,直接看代码 代码: # include <bits/stdc++.h> using namespace std ; int Last [ 10010 ] , Next [ 10010 ] , End [ 10010 ] , n , m , x

[模板]LCA的倍增求法解析

旧街凉风 提交于 2020-03-05 06:58:02
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。 输入输出格式 输入格式: 第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。 接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。 接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果。 输入输出样例 输入样例#1: 5 5 4 3 1 2 4 5 1 1 4 2 4 3 2 3 5 1 2 4 5 输出样例#1: 4 4 1 4 4 说明 时空限制:1000ms,128M 数据规模: 对于30%的数据:N<=10,M<=10 对于70%的数据:N<=10000,M<=10000 对于100%的数据:N<=500000,M<=500000 样例说明: 该树结构如下: 第一次询问:2、4的最近公共祖先,故为4。 第二次询问:3、2的最近公共祖先,故为4。 第三次询问:3、5的最近公共祖先,故为1。 第四次询问:1、2的最近公共祖先,故为4。 第五次询问:4、5的最近公共祖先,故为4。 故输出依次为4、4、1、4、4。 Solution: 题目来源:Luogu P3379 我们来讲讲LCA的倍增求法,来自于LS学长神犇的教授

Codeforces 555E. Case of Computer Network 题解

情到浓时终转凉″ 提交于 2020-03-03 17:13:29
题目链接: E. Case of Computer Network 题目大意:给定一张 \(n\) 个点 \(m\) 条边的无向图( 图不一定联通 ),给定 \(q\) 组有向点对 \((s_i,t_i)\) ,问是否有一种边的定向方式,使得 \(q\) 组点对都可以从 \(s_i\) 到达 \(t_i\) 。 题解: 不会求边双的菜鸡自闭了。 这一题,如果整个图是一个边双联通分量的话,因为每两个点之间都有至少两条路径,一定符合条件。那么很明显可以想到可以直接将原图边双缩点,最后得到的结果就是一片森林,如果有任意一组 \((s_i,t_i)\) 不在同一棵树内,直接输出 No 即可,对于另外的限制,通过在在树上打标记来实现,具体操作就是:令 \(lca_i=\text{LCA}(s_i,t_i)\) ,那么就是从 \(s_i\) 到 \(lca_i\) 的边全部向上,从 \(lca_i\) 到 \(t_i\) 的边全部向下,所以用两个标记 \(tag_{1,u},tag_{2,u}\) ,一个 \(u\) --> \(fa_u\) 边的方向向上的点对数,另一个表示 \(fa_u\) --> \(u\) 边的方向向下的点对数,所以,在一个点上如果 \(tag_{1,u}>0\text{且}tag_{2,u}>0\) 时,很明显出现矛盾,输出 No ,如果所有的点都合法,那么输出

CF704E Iron Man

痴心易碎 提交于 2020-03-03 12:07:57
cf 先考虑暴力做法.对于每条路径,显然可以拆到路径上的每条边上,然后记录一下这个路径经过这条边的起始时间 \(xl\) 和终止时间 \(xr\) .然后在平面直角坐标系上,上行的边对应连接 \((xl,0),(xr,1)\) ,下行的边对应连接 \((xl,1),(xr,0)\) ,那么这条边的贡献就是所有线段交点的横坐标最小值 因为给出的是一段路径,我们可以联想到树剖,把一条路径拆在 \(log\) 条重链上,然后对于每条重链统计答案.对于一条路径,设它经过这个重链的起始时间 \(xl\) 对应所在深度为 \(yl\) ,终止时间 \(xr\) 对应所在深度为 \(yr\) ,那么在平面上连接 \((xl,yl),(xr,yr)\) .现在问题变成求一个线段集合的交点横坐标最小值.这里对横坐标做扫描线,每条线段对应会在起始横坐标被加入,在终止横坐标被删除.我们维护代表所有经过当前扫描线的multiset,按照线段在当前 \(x\) 的纵坐标为关键字排序.由于一条线段最早只会和上下两条线段相交,所以加入一条线段时就用当前线段和前驱线段的交点横坐标和当前线段和后继线段的交点横坐标更新答案;当删除一个线段时,这个线段的前驱和后继会相邻,那么用前驱和后继的交点更新答案 以及你可能要注意yi些细节,例如重链顶端到父亲的那条边也要算进重链;求两个线段交点要考虑线段重合问题

洛谷P1967 货车运输 生成树+LCA 倍增

故事扮演 提交于 2020-02-28 00:05:33
题目链接:https://www.luogu.com.cn/problem/P1967 这题我们可以知道有些边是肯定不会用到的,所以我们想办法去边。把这个图的最大生成树求出来即可。然后求两点的最小限重,用树上倍增求LCA,过程种更新最小限重。 代码如下 # include <bits/stdc++.h> using namespace std ; const int maxn = 1e4 + 5 ; const int maxm = 5e4 + 5 ; const int inf = 0xfffffff ; struct Node { int x , y , w ; } edge1 [ maxm ] ; //存原图 struct node { int to , next , value ; } edge2 [ maxm * 2 ] ; //存最大生成树 //无向边开两倍 int cnt ; int n , m , q ; int head [ maxn ] ; int f [ maxn ] ; //存祖先节点 int fa [ maxn ] [ 21 ] ; //存生成树父节点 int weight [ maxn ] [ 21 ] ; //存最小限重 int depth [ maxn ] ; //存每个点深度 void add ( int x , int y , int z ) /

對於樹上倍增LCA的復習

此生再无相见时 提交于 2020-02-26 10:41:28
今年一年之内數場比賽都考到了樹上倍增LCA。(可見其之重要性) 於是,我們不如來復習一波。。 LCA(Least Common Ancestors) 即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。 常见解法一般有三种 这里讲解一种在线算法—倍增 首先我们定义fa[u][j]表示结点u的第2^j祖先 那么要怎么求出全部的fa数组呢 不难发现fa[u][0]就是u的父亲结点 这些父亲结点我们可以直接初始化 对于其他结点则有 fa[u][j]=fa[ fa[u][j-1] ] [j-1] 什么意思呢 u的第2^(j-1)祖先的第2^(j-1)祖先 就是u的第2^j祖先(有点像快速幂那样分解) 预处理各节点深度+初始fa[u][0] void dfs(int u,int pa) { dep[u]=dep[pa]+1; fa[u][0]=pa; for(int i=head[u];i;i=E[i].nxt) { int v=E[i].v; if(v!=pa) dfs(v,u); } } 预处理fa数组 for(int i=1;(1<<i)<=n;i++) for(int u=1;u<=n;u++) fa[u][i]=fa[ fa[u][i-1] ][i-1]; 预处理之后怎么求解LCA(u,v)呢 我么先假定dep[u]>dep[v] 则两点深度差 d=dep[u]