Codevs2370 小机房的树
2015-08-10 14:56
357 查看
题目大意:给定一棵无根树,树边带权,求树上两点的最近距离。
思路:典型的LCA问题,采用倍增的方法。这里介绍一下倍增法求LCA。记数组fa[i,j]表示节点i向上走2j2^j步所能达到的点,在给出直接的父子u,v时记录下fa[u,0]=v,此后利用fa[i][j]=fa[fa[i][j-1]][j-1]就能得到其它的值。利用dfs获得各个节点的深度dep[ ]。节点u,v在寻找LCA时,令dep[u]>dep[v],再让u向上直至dep[u]=dep[v],最后二者一起向上找,直至fa[u,0]=fa[v,0],此时停止寻找,则LCA=fa[u,0]。寻找时,令j从大到小枚举,发现fa[u,j]!=fa[v,j]就往上蹦2j2^j步。若要记录花费,只需使用数组g[i,j]表示从节点i向上蹦2j2^j步的费用,很容易得到g[i,0]=c以及g[i][j]=g[fa[i][j-1]][j-1]+g[i][j-1]。
注意:这是一个无向图,需要自己选定树根,这里我选的是0,并且需要双向存边,并在DFS中确定树的父子节点关系。
代码如下:
思路:典型的LCA问题,采用倍增的方法。这里介绍一下倍增法求LCA。记数组fa[i,j]表示节点i向上走2j2^j步所能达到的点,在给出直接的父子u,v时记录下fa[u,0]=v,此后利用fa[i][j]=fa[fa[i][j-1]][j-1]就能得到其它的值。利用dfs获得各个节点的深度dep[ ]。节点u,v在寻找LCA时,令dep[u]>dep[v],再让u向上直至dep[u]=dep[v],最后二者一起向上找,直至fa[u,0]=fa[v,0],此时停止寻找,则LCA=fa[u,0]。寻找时,令j从大到小枚举,发现fa[u,j]!=fa[v,j]就往上蹦2j2^j步。若要记录花费,只需使用数组g[i,j]表示从节点i向上蹦2j2^j步的费用,很容易得到g[i,0]=c以及g[i][j]=g[fa[i][j-1]][j-1]+g[i][j-1]。
注意:这是一个无向图,需要自己选定树根,这里我选的是0,并且需要双向存边,并在DFS中确定树的父子节点关系。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; struct node { int id,len; node(int id=0,int len=0):id(id),len(len){} }; const int maxn=50005; int n,m,costi[maxn],fa[maxn][25],g[maxn][20],dep[maxn]; int ans; bool vis[maxn]; vector<node> son[maxn]; void build(int root,int depth) { dep[root]=depth; vis[root]=1; vector<node>::iterator it; for (it=son[root].begin();it!=son[root].end();++it) { if (!vis[(*it).id]) { fa[(*it).id][0]=root; g[(*it).id][0]=(*it).len; build((*it).id,depth+1); } } } int adjust(int u,int step) { for (int j=20;j>=0;--j) { if ((1<<j)<=step) { ans+=g[u][j]; u=fa[u][j]; step-=(1<<j); if (step==0) return u; } } } void query(int u,int v) { ans=0; if (u==v) { printf("0"); return; } if (dep[u]<dep[v]) swap(u,v); if (dep[u]!=dep[v]) u=adjust(u,dep[u]-dep[v]); for (int j=20;j>=0;--j) if (fa[u][j]!=fa[v][j]) { ans+=g[u][j]; ans+=g[v][j]; u=fa[u][j]; v=fa[v][j]; } if (u!=v) { ans+=g[u][0]; ans+=g[v][0]; } printf("%d\n",ans); } void init() { scanf("%d",&n); int u,v,c; memset(fa,0,sizeof(fa)); memset(vis,0,sizeof(vis)); for (int i=1;i<=n-1;++i) { scanf("%d%d%d",&u,&v,&c); son[u].push_back(node(v,c)); son[v].push_back(node(u,c)); } build(0,0); for (int j = 1; j < 20; ++j) for (int i = 1; i <= n; ++i) { fa[i][j]=fa[fa[i][j-1]][j-1]; g[i][j]=g[fa[i][j-1]][j-1]+g[i][j-1]; } scanf("%d",&m); while (m--) { scanf("%d%d",&u,&v); query(u,v); } } int main() { init(); return 0; }
相关文章推荐
- UIPasteboard Example – Read, Write and Share data between apps
- JS中Cookie详解及示例展示
- 内存分配方式
- 一个服务接口的多个实现的选择
- LCS 最大子段和,最大子段和在原数组的首末地址
- 【ecos】service
- hdu 3338 网络流填数字
- Java双缓冲技术
- apache tomcat集群
- 排列、组合相关知识
- 线段树(二)区间更新
- 静态代码块,构造代码块和构造函数的区别
- 中文分词与停用词的作用
- Java开发web的几种开发模式
- Retrofit 介绍
- apache tomcat集群
- QT调用CHM方法
- shared_ptr/unique_ptr一点体会
- #笔记#圣思园 JavaWeb 第2讲——CSS层叠样式表Cascading Style Sheets
- find 常用命令