想探讨一下lca问题的倍增解法
以洛谷第3379题为例
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
//建树邻接表;
int n,m,s,x,y,a,b,ans[500005];
int fir[500005],nex[500005],to[500005],tot,top;
int dep[500004],f[500005][22];
void build(int x,int y){
to[++tot]=y;
nex[tot]=fir[x];
fir[x]=tot;
}
inline int read(){
int X=0,w=0; char ch=0;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
//预处理;
void deal_f(int u,int father){
dep[u]=dep[father]+1;
for(int i=0;i<=19;i++)
f[u][i+1]=f[f[u][i]][i];//推出来的;
for(int e=fir[u];e;e=nex[e]){
int v=to[e];
if(v==father) continue;//不处理,无意义;
f[v][0]=u;
deal_f(v,u);//找寻相关子父点;
}
}
//LCA,自己仔细想一下;
int lac(int a,int b){
if(dep[a]<dep[b]) swap(a,b);
for(int i=20;i>=0;i--){
if(dep[f[a][i]]>=dep[b]) a=f[a][i];//从上下调;
if(a==b) return a;
}
for(int i=20;i>=0;i--){
if(f[a][i]!=f[b][i]){
a=f[a][i];
b=f[b][i];
}
}
return f[a][0];
}
int main(){
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=n-1;i++){
x=read();y=read();//scanf("%d%d",&x,&y);
build(x,y);build(y,x);//无向图;
}
deal_f(s,0);//因题中已确定根节点;
for(int i=1;i<=m;i++){
a=read();b=read();//scanf("%d%d",&a,&b);
ans[i]=lac(a,b);
}
for(int i=1;i<=m;i++){
printf("%d\n",ans[i]);
}
}
假如用这个代码有三个点过不去。
究其原因是时间超限。
那么解决方法是(参考了大佬的解决方法,但在此具体提出,为我们这些有点晕的人)
那就是你没注意数组的大小,我边打边写现在想哭3个小时就是因为数组开小了;
将题中nex数组×2和to数组×2,即可;
第一次写有点水,见谅;