<学习笔记> 倍增 lca
简单来说就是给你一个n个点的树,每一条边都有边权。询问有m次,每次给出两个点,求他们之间的最小边权和。
很容易想到用求树上前缀和和lca,先把两个点跳到高度相同的地方,再一直往上跳,直到两个点重合。因为一个点一个点的跳太慢了,所以我们倍增的跳来求lca。
令f[i][j]表示i号点往上跳2^j步的父亲。
则 f[i][j]=f[f[i][j-1]][j-1];
这里有两个板子,思想都一样。
板子一
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 8 int n,m,u,v,c,cnt; 9 int sum[50010],deep[50010],fa[50010][30],first[50010],next[100020]; 10 struct maple{ 11 int f,t,d; 12 }Rode[100020]; 13 14 void build(int f,int t,int d) //注意双向建边 15 { 16 Rode[++cnt]=(maple){f,t,d}; 17 next[cnt]=first[f]; 18 first[f]=cnt; 19 } 20 void dfs(int f,int t,int d) // dfs处理出树 21 { 22 deep[t]=deep[f]+1; 23 fa[t][0]=f; 24 sum[t]=d; 25 for(int i=first[t];i;i=next[i]) 26 if(Rode[i].t!=f) 27 dfs(t,Rode[i].t,d+Rode[i].d); 28 } 29 void Done() // 预处理倍增跳的fa 30 { 31 for(int i=1;i<=log2(n);++i) 32 for(int j=0;j<=n;++j) 33 fa[j][i]=fa[fa[j][i-1]][i-1]; // j往上跳2^i等同于fa[j][i-1]往上跳i-1步,这里与st表有细微区别 34 } 35 int lca(int x,int y) 36 { 37 if(deep[x]<deep[y]) swap(x,y); //确保x的深度大 38 for(int i=log2(n);i>=0;--i) // 把x跳到与y深度相同的地方 39 { 40 if(deep[fa[x][i]]>=deep[y]) 41 x=fa[x][i]; 42 } 43 if(x==y) return x; 44 for(int i=log2(n);i>=0;--i) //一起往上跳 45 if(fa[x][i]!=fa[y][i]) 46 x=fa[x][i],y=fa[y][i]; 47 return fa[x][0]; 48 } 49 int main() 50 { 51 scanf("%d",&n); 52 for(int i=1;i<n;++i) 53 { 54 scanf("%d%d%d",&u,&v,&c); 55 build(u,v,c); 56 build(v,u,c); 57 } 58 dfs(0,0,0); 59 Done(); 60 scanf("%d",&m); 61 while(m--) 62 { 63 scanf("%d%d",&u,&v); 64 printf("%d\n",sum[u]+sum[v]-2*sum[lca(u,v)]); 65 } 66 return 0; 67 }
板子二
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 8 int n,u,v,c,m; 9 int first[150010],next[150010],fa[150010][30],deep[150010],cnt; 10 int de[60000]; 11 struct maple{ 12 int f,t,d; 13 }rode[150010]; 14 15 void done(int f,int t,int v) 16 { 17 fa[t][0]=f; 18 deep[t]=deep[f]+1; 19 de[t]=de[f]+v; 20 for(int i=1;fa[t][i-1];++i) 21 fa[t][i]=fa[fa[t][i-1]][i-1]; 22 for(int i=first[t];i!=-1;i=next[i]) 23 if(rode[i].t!=f) 24 done(t,rode[i].t,rode[i].d); 25 } 26 void build(int f,int t,int d) 27 { 28 rode[++cnt]=(maple){f,t,d }; 29 next[cnt]=first[f]; 30 first[f]=cnt; 31 } 32 int lca(int x,int y) 33 { 34 if(deep[x]<deep[y]) swap(x,y); 35 if(deep[x]>deep[y]) 36 { 37 int l=deep[x]-deep[y]; 38 for(int i=0;i<=20;++i) 39 if(l>>i&1) 40 x=fa[x][i]; 41 } 42 if(x==y) return x; 43 for(int i=log2(n);i>=0;--i) 44 if(fa[x][i]!=fa[y][i]) 45 x=fa[x][i],y=fa[y][i]; 46 return fa[x][0]; 47 } 48 49 int main() 50 { 51 memset(next,-1,sizeof(next)); 52 memset(first,-1,sizeof(first)); 53 scanf("%d",&n); 54 for(int i=1;i<n;++i) 55 { 56 scanf("%d%d%d",&u,&v,&c); 57 build(u,v,c); 58 build(v,u,c); 59 } 60 done(0,0,0); 61 scanf("%d",&m); 62 while(m--) 63 { 64 scanf("%d%d",&u,&v); 65 printf("%d\n",de[u]+de[v]-2*de[lca(u,v)]); 66 } 67 return 0; 68 }