BNU 24258 Journey (LCA)

文章探讨了在树形结构中添加一条新道路后,如何通过计算路径长度来优化旅行时间。具体步骤包括建立原始图、求解节点间的最短路径、构建层次结构并应用倍增法求LCA(最近公共祖先),最终计算添加道路后的路径节省时间。通过实例演示了解决方案。
摘要由CSDN通过智能技术生成

Bob has traveled to byteland, he find the N cities in byteland formed a tree structure, a tree structure is very special structure, there is exactly one path connecting each pair of nodes, and a tree with N nodes has N - 1 edges.

As a traveler, Bob wants to journey between those N cities, and he know the time each road will cost. he advises the king of byteland building a new road to save time, and then, a new road was built. Now Bob has Q journey plan, give you the start city and destination city, please tell Bob how many time is saved by add a road if he always choose the shortest path. Note that if it's better not journey from the new roads,
the answer is 0.

Input

First line of the input is a single integer T(1 <= T <= 20), indicating there are T test cases.

For each test case, the first will line contain two integers N(2 <= N <= 10^5) and Q(1 <= Q <= 10^5), indicating the number of cities in byteland and the journey plans. Then N line followed, each line will contain three integer x, y(1 <= x,y <= N) and z(1 <= z <= 1000) indicating there is a road cost z time connect the x-th city and the y-th city, the first N - 1 roads will form a tree structure, indicating the original roads, and the N-th line is the road built after Bob advised the king. Then Q line followed, each line will contain two integer x and y(1 <= x,y <= N), indicating there is a journey plan from the x-th city to y-th city.

Output

For each case, you should first output "Case #t:" in a single line, where t indicating the case number between 1 and T, then Q lines followed, the i-th line contains one integer indicating the time could saved in i-th journey plan.

题意:给出n个结点的树,q次询问,然后给出一条额外添加的边,从a到b距离为c。q次询问,给出u,v,询问uv的最短距离比原来短多少。

思路:按原图建图,然后已b为根求出到其他点的dis,
uv=dis[u]+dis[v]-2*dis[lca(u,v)]; 
tem=min(ua+vb,ub+va)+c; 
ans=max(0,uv-ans);

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
#define N 100005
struct node
{
    int u,v,w,next;
} e[2*N];
int head[N],dis[N],visit[N],pre[N],rrank[N],use[N];
int k;
void init()
{
    k=0;
    memset(head,-1,sizeof(head));
}
void add(int u,int v,int w)
{
    e[k].u=u;
    e[k].v=v;
    e[k].w=w;
    e[k].next=head[u];
    head[u]=k++;
}
int fa[N][20],dep[N];
void dfs(int u)
{
    use[u]=1;
    for(int i=head[u]; i!=-1; i=e[i].next)
    {
        int v=e[i].v;
        if(!use[v])
        {
            dis[v]=dis[u]+e[i].w;
            rrank[v]=rrank[u]+1;
            pre[v]=u;
            dfs(v);
        }
    }
}
/*倍增法求LCA nlogn*/
void bfs(int root)
{
    queue<int>q;
    dep[root]=0;
    fa[root][0]=root;
    q.push(root);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=1; i<20; i++)
            fa[u][i]=fa[fa[u][i-1]][i-1];
        for(int i=head[u]; i!=-1; i=e[i].next)
        {
            int v=e[i].v;
            if(v==fa[u][0]) continue;
            dep[v]=dep[u]+1;
            fa[v][0]=u;
            q.push(v);
        }
    }
}
int lca(int u,int v)
{
    if(dep[u]>dep[v]) swap(u,v);
    int hu=dep[u],hv=dep[v];
    int tu=u,tv=v;
    for(int det=hv-hu,i=0; det; det>>=1,i++)
    {
        if(det&1)
            tv=fa[tv][i];
    }
    if(tv==tu) return tu;
    for(int i=19; i>=0; i--)
    {
        if(fa[tu][i]==fa[tv][i]) continue;
        tu=fa[tu][i];
        tv=fa[tv][i];
    }
    return fa[tu][0];
}
int main()
{
    int T,n,m,i,q,t=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&q);
        m=n-1;
        init();
        int u,v,w;
        for(i=0; i<m; i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
        }
        memset(dis,0,sizeof(dis));
        memset(pre,0,sizeof(pre));
        memset(use,0,sizeof(use));
        memset(rrank,0,sizeof(rrank));
        memset(dep,0,sizeof(dep));
        memset(fa,0,sizeof(fa));
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        dfs(b);//求dis
        bfs(b);
        printf("Case #%d:\n",t++);
        while(q--)
        {
            scanf("%d%d",&u,&v);
            int ua=dis[u]+dis[a]-2*dis[lca(u,a)];
            int vb=dis[v];
            int ub=dis[u];
            int va=dis[v]+dis[a]-2*dis[lca(v,a)];
            int uv=dis[u]+dis[v]-2*dis[lca(u,v)];
            int ans=min(ua+vb,ub+va)+c;
            printf("%d\n",max(0,uv-ans));
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值