-
G - How far away ?
- HDU - 2586
- 题意:
- n个房子用n-1条路连接起来(也就是一棵树),对于每一个询问,
- 求出2个房子直接的线路距离
- 思路:
- 这个题目只要建立一个树,然后查询任意2个点之间的距离,假设B和C的最近公共祖先是A,那么对于整个树的根节点D,
- 都有:|BD|+|CD|-|AD|*2=|BC|事先求出所有点到1的距离d,
- 分析:倍增求LCA
- deep[x],表示x节点的深度。
- ans[x][i] ,这个数组表示标号为x节点向上跳2^i步的节点。dfs时预处理ans[x][0]=所有节点向上跳一个就是他的父亲节点。
- ans[x][1]=ans[ans[x][0]][0];例如2^4=2^3+2^3。x向上跳2的i次的节点=x向上跳i-1次方的这个节点向上跳i-1次方
- 给定两个节点。要我们求他们的lca 我们是把深度高的向上调。调整跟深度低的一样。首先我们j从log2(n)开始跳,跳到0。我们要跳到他们lca的下面两个节点
-
#include<bits/stdc++.h> using namespace std; #define maxn 40006 int deep[maxn],d[maxn],t; int ans[maxn][20],k,n; struct node { int v,w; }; vector<node>mmp[maxn]; void dfs(int u,int pre,int depth,int dis) { ans[u][0]=pre; d[u]=dis; deep[u]=depth; int len=mmp[u].size(); for(int i=0; i<len; i++) { int v=mmp[u][i].v; if(v==pre)continue; dfs(v,u,depth+1,dis+mmp[u][i].w); } } void init() { for(int j=1; (1<<j)<n; j++) { k=j; for(int i=1; i<=n; i++) { ans[i][j]=-1; int temp=ans[i][j-1]; if(temp==-1) continue; ans[i][j]=ans[temp][j-1]; } } } int lca(int u,int v) { if(deep[u]<deep[v])swap(u,v); for(int i=k; i>=0; i--) if(deep[u]-(1<<i)>=deep[v]) u=ans[u][i]; if(u==v) return u; for(int i=k; i>=0; i--) if(ans[u][i]!=ans[v][i]) { u=ans[u][i]; v=ans[v][i]; } return ans[u][0]; } int main() { ios::sync_with_stdio(false); cin>>t; while(t--) { int m,u,v,w; cin>>n>>m; for(int i=1; i<=n; i++) mmp[i].clear(); for(int i=1; i<n; i++) { cin>>u>>v>>w; mmp[u].push_back((node) { v,w }); mmp[v].push_back((node) { u,w }); } dfs(1,-1,1,0); init(); while(m--) { cin>>u>>v; int fa=lca(u,v); cout<<d[u]+d[v]-2*d[fa]<<endl; } } return 0; }
G - How far away - 倍增LCA模板
最新推荐文章于 2019-08-28 19:06:21 发布