hnu 12029 LCA问题

本文介绍了一种解决蚂蚁巢穴间最短路径的问题,通过构建隧道连接不同蚁丘,使用Tarjan算法找到最小公共祖先来计算任意两个蚁丘间的最短距离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Ants Colony
Time Limit: 5000ms, Special Time Limit:15000ms, Memory Limit:65536KB
Total submit users: 13, Accepted users: 6
Problem 12029 : No special judgement
Problem description
A group of ants is really proud because they built a magnificent and large colony. However, the enormous size has become a problem, because many ants do not know the path between some parts of the colony. They desperately need your help! 
The colony of ants was made as a series of N anthills, connected by tunnels. The ants, obsessive as they are, numbered the anthills sequentially as they built them. The first anthill, numbered 0, did not require any tunnel, but for each of the subsequent anthills, 1 through N - 1, the ants also built a single tunnel that connected the new anthill to one of the existing anthills. Of course, this tunnel was enough to allow any ant to go to any previously built anthill, possibly passing through other anthills in its path, so they did not bother making extra tunnels and continued building more anthills. 
Your job is, given the structure of the colony and a set of queries, calculate for each query the shortest path between pairs of anthills. The length of a path is the sum of the lengths of all tunnels that need to be traveled. 

Input
Each test case is given using several lines. The first line contains an integer N representing the number of anthills in the colony (2 ≤ N ≤ 105). Each of the next N - 1 lines contains two integers that describe a tunnel. Line i, for 1 ≤ i ≤ N - 1, contains Ai and Li, indicating that anthill i was connected directly to anthill Ai with a tunnel of length Li (0 ≤ Ai ≤ i - 1 and 1 ≤ Li ≤ 109). The next line contains an integer Q representing the number of queries that follow (1 ≤ Q ≤ 105). Each of the next Q lines describes a query and contains two distinct integers S and T (0 ≤ S, T ≤ N - 1), representing respectively the source and target anthills. 
The last test case is followed by a line containing one zero. 

Output
For each test case output a single line with Q integers, each of them being the length of a shortest path between the pair of anthills of a query. Write the results for each query in the same order that the queries were given in the input. 

Sample Input
6
0 8
1 7
1 9
0 3
4 2
4
2 3
5 2
1 4
0 3
2
0 1
2
1 0
0 1
6
0 1000000000
1 1000000000
2 1000000000
3 1000000000
4 1000000000
1
5 0
0
Sample Output
16 20 11 17
1 1
5000000000
Problem Source

ACM ICPC2010 ? Latin American Regional

分析:这题很明显是最小公共祖先问题,比赛时敲模板,敲完一直wa。。。结束才发现悲剧地输出没换行委屈

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=111111;
const int maxk=111111;
struct edge
{
    int v,next;
    __int64 w;
}g[maxn*2],q[maxk*2];
int headg[maxn],headq[maxn],parent[maxn],pos1,pos2,n,m,k,a,b,c;
__int64 ans[maxk],dis[maxn];
bool vis[maxn];
inline void add1(int a,int b,int c)
{
    g[pos1].next=headg[a];
    g[pos1].v=b;
    g[pos1].w=c;
    headg[a]=pos1++;
}
inline void add2(int a,int b,int c)
{
    q[pos2].next=headq[a];
    q[pos2].v=b;
    q[pos2].w=c;
    headq[a]=pos2++;
}
int find(int a)
{
    if(parent[a]==-1)return a;
    return parent[a]=find(parent[a]);
}
void tarjan(int u)
{
    vis[u]=1;
    int v,i;
    for(i=headq[u]; i; i=q[i].next)
        if(vis[v=q[i].v])ans[q[i].w]=dis[u]+dis[v]-2*dis[find(v)];
    for(i=headg[u]; i; i=g[i].next)
        if(!vis[v=g[i].v])
        {
            dis[v]=dis[u]+g[i].w;
            tarjan(v);
            parent[v]=u;
        }
}
int main()
{
    while(scanf("%d",&n),n)
    {
        memset(headg,0,sizeof(headg));
        memset(headq,0,sizeof(headq));
        memset(vis,0,sizeof(vis));
        for(int i=0; i<=n; ++i)parent[i]=-1;
        pos1=pos2=1;
        for(int i=1; i<n; ++i)
        {
            scanf("%d%d",&b,&c);
            add1(i,b,c);
            add1(b,i,c);
        }
        scanf("%d",&m);
        for(int i=1; i<=m; ++i)
        {
            scanf("%d%d",&a,&b);
            add2(a,b,i);
            add2(b,a,i);
        }
        dis[0]=0;
        tarjan(0);
        for(int i=1; i<m; ++i)printf("%I64d ",ans[i]);
        printf("%I64d\n",ans[m]);
    }
    return 0;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值