HDU-2586,LCA模板题
HDU-2586 How far away ?
题目大意:给你n个节点组成的树,树的每条边上都有一定的权值,问你树上两点之间的
距离是多少
具体思路:此题是在学习tarjan中找到的一道题,由于题目给出的是一个树,可以联想到
子节点与根节点之间的关系,我们可以通过dfs求出子节点与根节点之间的距离,对于树中
任意的两个子节点到根节点中,总有重合的部分,然而这部分是不用计算在内的。因此我们可以求出
距离两个子节点比较近的节点再减去这个节点到根节点的距离就是了,因此我们要求两个点的最近公共祖先
LCA讲解:https://www.cnblogs.com/JVxie/p/4854719.html
题目可以有两种解法,第一种是通过倍增求LCA在线处理,第二种是dfs离线处理
#include<iostream>//第一种 #include<vector> #include<algorithm> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int maxn=400004; struct node { int to,w; node(int a=0,int b=0){ to=a; w=b; } }; vector<node>q[maxn]; int f[maxn],p[maxn][20],deep[maxn],dis[maxn],n; void dfs(int u,int pre,int t) { deep[u]=t; f[u]=pre; for(int i=0;i<q[u].size();i++) { int v=q[u][i].to; if(v!=pre) { dis[v]=dis[u]+q[u][i].w; dfs(v,u,t+1); } } } //int a[100005]; void init() { int i,j; for(j=0;(1<<j)<=n;j++) { for( i=1;i<=n;i++) { p[i][j]=-1; } } for(int i=1;i<=n;i++) p[i][0]=f[i]; for(j=1;(1<<j)<=n;j++) { for (i=1;i<=n;i++) { if(p[i][j-1]!=-1) p[i][j]=p[p[i][j-1]][j-1]; } } } int lca(int a,int b) { int i,j; if(deep[a]<deep[b]) swap(a,b); for(i=0;(1<<i)<=deep[a];i++) { } i--; for(j=i;j>=0;j--) { if(deep[a]-(1<<j)>=deep[b]) a=p[a][j]; } if(a==b)return a; for(j=i;j>=0;j--) { if(p[a][j]!=-1&&p[a][j]!=p[b][j]) { a=p[a][j]; b=p[b][j]; } } return f[a]; } int main() { int t; cin>>t; while(t--) { int m; cin>>n>>m; for(int i=1;i<=n;i++) q[i].clear(); for(int i=1;i<n;i++) { int a,b,c; cin>>a>>b>>c; q[a].push_back(node(b,c)); q[b].push_back(node(a,c)); } dis[1]=0; dfs(1,-1,0); init(); while(m--) { int a,b; cin>>a>>b; int ans=dis[a]+dis[b]-2*dis[lca(a,b)]; cout<<ans<<endl; } } return 0; }
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream>//第二种 #include<vector> #include<algorithm> using namespace std; const int maxn=4e5+4; struct node { int to,w; node(int a=0,int b=0) { to=a; w=b; } }; vector<node>q[maxn]; vector<node>e[maxn]; int f[maxn],dis[maxn],vis[maxn],n,ans[maxn]; int finds(int x) { if(x==f[x]) return x; else return f[x]=finds(f[x]); } void lca(int u) { vis[u]=1; for(int i=0;i<q[u].size();i++) { int v=q[u][i].to; if(vis[v]) continue; //vis[v]=1; dis[v]=dis[u]+q[u][i].w; lca(v); f[v]=u; for(int j=0;j<e[v].size();j++) { int c=e[v][j].to; if(vis[c]&&ans[e[v][j].w]==-1) { if(v==c) ans[e[v][j].w]=0; else ans[e[v][j].w]=dis[c]+dis[v]-2*dis[finds(c)]; } } } } int main() { int t; cin>>t; while(t--) { int m; cin>>n>>m; for(int i=1;i<=n;i++) { q[i].clear(); e[i].clear(); vis[i]=0; f[i]=i; ans[i]=-1; } for(int i=1;i<n;i++) { int a,b,c; cin>>a>>b>>c; q[a].push_back(node(b,c)); q[b].push_back(node(a,c)); } for(int i=1;i<=m;i++){ int a,b; cin>>a>>b; e[a].push_back(node(b,i)); e[b].push_back(node(a,i)); } dis[1]=0; lca(1); for(int i=1;i<=m;i++) cout<<ans[i]<<endl; //cout<<endl; } }
以上解题思路来源于:https://blog.csdn.net/a601025382s/article/details/10615039