标签:roo 查询 它的 play isp 警告 算法 next std
还是济南集训的内容,让人头秃(不得不说两个老师讲了两遍我勉勉强强才搞懂一点点)
首先来看:
LCA就是最近公共祖先,至于它的含义,我觉得例题写的看起来会更清楚,请看:
好的,明白了它的含义后,我们很容易想到朴素算法:
#include<cstdio> #include<iostream> #include<cmath> using namespace std; const int maxn = 500005; const int maxe = 1000005; int n,m,root; struct line { int from,to; line(){}//空构造函数 line p; line(int A,int B){ //构造函数 line L=line(1,2); from=A;to=B; } }edge[maxe]; //上面是新建一个树 int last[maxn],_next[maxe],e; //last[x]表示以x为起点的最后一条边(的编号) //_next[i]表示与第i条边起点相同的上一条边(的编号) void add_edge(int x,int y) { edge[++e]=line(x,y); _next[e]=last[x]; last[x]=e; } //存边 int Fa[maxn][35],Dep[maxn]; void dfs(int x,int fa) { int i,k,y; Fa[x][0]=fa;//当前节点x的父亲节点fa Dep[x]=Dep[Fa[x][0]]+1; //x的深度是它父亲节点的深度+1 //记录当前节点的深度 k=ceil(log(Dep[x])/log(2)); //ceil函数是向上取整 //x往上倍增的上限 for(i=1;i<=k;i++)Fa[x][i]=Fa[Fa[x][i-1]][i-1]; //倍增计算祖先 ,记录 for(int i=last[x];i;i=_next[i])//枚举与x相邻的边 { int v=edge[i].to; if(v!=fa)dfs(v,x); } } int LCA(int x,int y) { int i,k,s; s=ceil(log(n)/log(2)); //该树倍增最大可能的上限 if(Dep[x]<Dep[y])swap(x,y); //交换x和y的值 /////////////x往上走k层,让x与y处于同一层 ////////// k=Dep[x]-Dep[y]; for(i=0;i<=s;i++) if(k&(1<<i))x=Fa[x][i]; if(x==y)return x; //x==y时,x就是最近公共祖先 /////////////////////////////////////////////////// s=ceil(log(Dep[x])/log(2)); //计算向上倍增的上限 for(i=s;i>=0;i--) if(Fa[x][i]!=Fa[y][i]){ x=Fa[x][i]; y=Fa[y][i]; } return Fa[x][0]; } int main() { int i,j,k; cin>>n>>m>>root; for(i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); add_edge(x,y); add_edge(y,x);//它是树,也就是无向图,所以存两次边 } dfs(root,0);//预处理 for(i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); printf("%d\n",LCA(x,y)); } }
OK吗?
这里建议去练练板子,指路-> https://www.luogu.org/problem/P3379
(哇我居然可以写蓝题了哎!!可喜可贺)
标签:roo 查询 它的 play isp 警告 算法 next std
原文地址:https://www.cnblogs.com/Phantomhive/p/11552874.html