树上倍增求LCA(RMQ)

匿名 (未验证) 提交于 2019-12-03 00:13:02

板子(反正我只是个垃圾)

//树上倍增求LCA(RMQ),其实就是个简单的二进制拆分问题 //正确性很容易证明,不证了 //思想:eg: 求x节点和y节点的Lca,比较 x 与 y 节点的深度,将树中深的节点跳到 //与浅的节点相同深度(由大到小循环),如果刚好为深度浅的节点,那么就找到了,否则一起向 //上跳,找到最小的j使得他们所跳的位置不同,但父节点是相同的,返回所跳位置的父节点就好了 #include<bits/stdc++.h>//板子 using namespace std; const int maxn = 1000010; int head[maxn]; int deep[maxn];//节点深度 struct{     int v,net; }edge[maxn];//链式前向星(ORZ,向大佬低头) int n,m,root,cnt; int f[maxn][21];//每个当前节点的第2 ^ j次方是哪个节点 inline void add_edge(int x,int y) {        edge[cnt].v = y;     edge[cnt].net = head[x];     head[x] = cnt++; }//加边 void dfs(int cur) {     for(int i=head[cur];i!=-1;i=edge[i].net)     {         if(!deep[edge[i].v])//如果节点未被访问过         {             deep[edge[i].v] = deep[cur] + 1;             f[edge[i].v][0] = cur;//父节点为cur             dfs(edge[i].v);         }     } }//求节点的深度 void PRE() {     for(int i=1;i<=19;++i)         for(int j=1;j<=n;++j)//n个节点预处理             f[j][i] = f[f[j][i-1]][i-1]; //拆分二进制 }//预处理 int LCA(int x,int y) {     if(deep[x] < deep[y])         swap(x,y);     for(int i=19;i>=0;--i)     {         if(deep[f[x][i]] >= deep[y])//上升到同一deep             x = f[x][i];     }     if(x == y)         return x;     //否则查找最小上升的     for(int i=19;i>=0;--i)     {         if(f[x][i]!=f[y][i])         {             x = f[x][i];             y = f[y][i];         }     }     return f[x][0]; } int main() {     ios::sync_with_stdio(false);    cin.tie(0),cout.tie(0);     memset(head,-1,sizeof(head));//边集起点为 u 第一次出现的位置     cin>>n>>m>>root;     cnt = 1;     int u,v;     for(int i=1;i!=n;++i)//树有n-1条边,且为双向,因为得求深度,还得向上跳     {         cin>>u>>v;         add_edge(u,v);         add_edge(v,u);     }     deep[root] = 1;//根的深度为1     dfs(root);     PRE();     for(int i=1;i<=m;++i)     {         cin>>u>>v;         cout<<LCA(u,v)<<'\n';     } }

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!