最近公共祖先lca(洛谷p3379)
【模板】最近公共祖先(LCA)
题目描述
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入格式
第一行包含三个正整数 $N,M,S$,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来 N-1 行每行包含两个正整数 x, y,表示 x 结点和 y 结点之间有一条直接连接的边(数据保证可以构成树)。
接下来 M 行每行包含两个正整数 a, b,表示询问 $a 结点和 $b$ 结点的最近公共祖先。
输出格式
输出包含 $M$ 行,每行包含一个正整数,依次为每一个询问的结果。
样例1
样例输入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
提示
对于 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。
前置:邻接表存图
代码实现:
struct zzz{ int t,nxt;//t存此结构体到的点,nxt存下一个要遍历的zzz结构体 }e[60005];//邻接表存图 int head[30005];//存“与第i个点相连的边” void _add(int x,int y)//将y存成与x相连的点 { e[++tot].t=y; e[tot].nxt=head[x]; head[x]=tot; } int main() { n=R(); for(int i=1;i<n;i++)//输入边 { int x,y; x=R(); y=R(); _add(x,y);//无向图:y与x相连,x与y相连 _add(y,x);//(有点拗口) } }
万恶之源:lca问题解决办法
1)暴力(蒟蒻限定):跳到相同高度,之后两个同时向上一个一个一个地跳;
2)倍增
初始化:lg[i] = j 意思为 2^j <= i <2^j+1;
for(int i=1;i<=n;++i) lg[i]=lg[i>>1]+1;//这行可换成lg[i]=lg[i-1]+(1<<lg[i-1]==i);
建树:定义 f[i] [x] 为 i 号节点的第2^x辈祖先
<