想探讨一下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 ",ans[i]); } }
假如用这个代码有三个点过不去。
究其原因是时间超限。
那么解决方法是(参考了大佬的解决方法,但在此具体提出,为我们这些有点晕的人)
那就是你没注意数组的大小,我边打边写现在想哭3个小时就是因为数组开小了;
将题中nex数组×2和to数组×2,即可;
第一次写有点水,见谅;