hdu2586 How far away

勇气小镇是一个有着n个房屋的小镇,为什么把它叫做勇气小镇呢,这个故事就要从勇气小镇成立的那天说起了,
修建小镇的时候,为了让小镇有特色,镇长特地只修了n-1条路,并且规定说,所有在勇气小镇的村民,每一次出门必须规划好路线,
路线必须满足在到达终点之前绝对不走回头路。每个人都要这样,不然那个人就不配在小镇生活下去,因为他没有这个勇气。
事实上,这并不能算一项挑战,因为n-1条路已经连通了每户人家,不回头地从起点到终点,只是一个时间上的问题。
由于小镇上的福利特别好,所以小懒入住了这个小镇,他规划了m次的行程,每次从L房屋到R房屋,他想问你他每次从L房屋到R房屋最少能走多少路。
Input
输入的第一行是一个整数t,表示有t组数据
每组数据第一行是n,m两个数字,分别表示小镇上房屋的个数,和小懒计划的行程的数量。
之后第2行到第n行,每行三个整数a,b,c表示,a房屋与b房屋之间连接着一条距离为c的小路。
第n+1行到第n+m行,每行两个整数,L,R,代表一次小懒的询问,也就是询问小懒从L房屋走到R房屋所走的最近距离为多少。
Output
对于每组测试数据输出m行,每行一个整数,代表小懒从询问的L到R需要走的最近的距离
Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3

2 2
1 2 100
1 2
2 1
Sample Output
10
25
100
100
t<=10
2<=n<=40000
1<=m<=200
1<=a<=n
1<=b<=n
1<=c<=40000
1<=L<=n
1<=R<=n

找最近公共祖先的模板,嗯,倍增,目前就学会了这个orz
(B站搜LCA,大佬讲的不错)
看代码先去看主函数。。。

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;
const int maxn=4e4+5;
const int maxbit=15;//根据maxn的值来的,表示2^maxbit次方
struct edge
{
int to;
int val;
};
int father[maxn][maxbit];//当前结点的父亲结点
int depth[maxn];//深度判断层数
int dis[maxn];//距离
vector<edge> G[maxn];//图
int lg[maxn];//log2(n)向下取整
void dfs(int nowp,int fa)
{
depth[nowp]=depth[fa]+1;//记录当前节点的深度
father[nowp][0]=fa;//表示当前节点向上寻找一层
for(int j=1;j<=lg[depth[nowp]]+1;j++)//当前节点向上寻找时最多不能超过其深度,故取
                                       j<=lg[depth[nowp]]+1
{
    father[nowp][j]=father[father[nowp][j-1]][j-1];//倍增算法表示
}
for(int i=0;i<G[nowp].size();i++)
{
    edge &e=G[nowp][i];
    if(e.to!=fa)
    {
        dis[e.to]=dis[nowp]+e.val;
        dfs(e.to, nowp);
    }
}
}

int LCA(int u,int v)
{
if(depth[u]<depth[v])//为了方便把u换成更深的那一个(在下面)
swap(u,v);
while(depth[u]!=depth[v])//u,v深度不同,向上寻找
u=father[u][lg[depth[u]-depth[v]]];
if(u==v)//相同时直接返回
return u;
for(int j=lg[depth[u]];j>=0;--j)//向上寻找,寻找完之后在lca的下一层
{
    if(father[u][j]!=father[v][j])
    {
        u=father[u][j];
        v=father[v][j];
    }
}
return father[u][0];
}

int main()
{
lg[0]=-1;
for(int i=1;i<maxn;i++)
{
    lg[i]=lg[i>>1]+1;
}
int t;
cin>>t;
while(t--)
{
    memset(father,0,sizeof(father));
    memset(depth,0,sizeof(depth));
    memset(dis,0,sizeof(dis));
    for(int i=0;i<maxn;i++)
    G[i].clear();//多组样例记得clear()
    int n,m;
    scanf("%d %d",&n,&m);
    int x,y,k;
    for(int i=1;i<=n-1;i++)
    {
        scanf("%d %d %d",&x,&y,&k);//存图
        G[x].push_back({y,k});
        G[y].push_back({x,k});
    }
    dfs(1,0);
    while(m--)
    {
        scanf("%d %d",&x,&y);
        int lca=LCA(x,y);
        printf("%d\n",(dis[x]-dis[lca])+(dis[y]-dis[lca]));
    }
}
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值