国际大学生程序设计竞赛例题_5.9距离

1,求树的两个结点之间的距离
2,解答:求u和v的最近公共祖先(LCA)
先做一次dfs,转化为求第一次出现的u和v之间深度最大的点即是它们的公共祖先.
3,实例代码:

#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;

const int maxn=20010;

struct node
{
int v;//孩子结点
int d;//到该节点的距离
};

//注意vector在树问题中的使用
vector<node> tree[maxn];

int dfsnum[maxn]; //记录遍历的节点
int depth[maxn]; //记录节点对应的深度
int first[maxn]; //记录结点第一次访问到时的下标
int dis[maxn];//记录个点到根的距离
int top; //记录总的步伐数
void dfs(int m,int f,int dep,int d) //当前节点编号,父节点编号,深度
{
dfsnum[top]=m;
depth[top]=dep;
first[m]=top;
dis[m]=d;
top++;
for(unsigned i=0;i<tree[m].size();i++)
{
if(tree[m][i].v==f)
continue;
dfs(tree[m][i].v,m,dep+1,d+(tree[m][i].d));
dfsnum[top]=m; //注:每条边回溯一次,所以top的值=n+n-1
depth[top]=dep;
top++;
}
}

int dp[maxn][18];
void makeRmqIndex(int n,int b[]) //返回最小值对应的下标
{
int i,j;
for(i=0;i<n;i++)
dp[i][0]=i;
for(j=1;(1<<j)<=n;j++)
for(i=0;i+(1<<j)-1<n;i++)
dp[i][j]=b[dp[i][j-1]] < b[dp[i+(1<<(j-1))][j-1]]? dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
}
int rmqIndex(int s,int v,int b[])
{
int k=(int)(log((v-s+1)*1.0)/log(2.0));
return b[dp[s][k]]<b[dp[v-(1<<k)+1][k]]? dp[s][k]:dp[v-(1<<k)+1][k];
}


int n,qnum;//边数和询问数
int cnt;//测试数目
int main()
{
freopen("5.9.in","r",stdin);
cin>>cnt;
while(cnt--)
{
cin>>n>>qnum; //n是节点数
for(int i=0;i<n;i++)
tree[i].clear();
top=0;
int x,y,d;
node temp;
for(int i=0;i<n-1;i++)
{
cin>>x>>y>>d;
x--,y--;
temp.d=d;
temp.v=y;
tree[x].push_back(temp);
temp.v=x;
tree[y].push_back(temp);
}
dfs(0,-1,0,0);
makeRmqIndex(top,depth);
while(qnum--)
{
cin>>x>>y;
x--,y--;
if(first[x]>first[y])
{
d=x;
x=y;
y=d;
}
int lca=dfsnum[rmqIndex(first[x],first[y],depth)];//得到lca
cout<<dis[x]+dis[y]-2*dis[lca]<<endl;
}
}
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值