周赛第二次的题目。传说中的最近公共祖先问题(LCA),用Tarjan算法可以过,但注意结果超int.
从题意可以看出这些colony之间构成了一棵树的关系,用Tarjan算法找出每对查询的顶点u,v的公共祖先ancestor,则u,v之间的距离就是dist[u]+dist[v]-2*dist[ancestor],关系显而易见,会者不难。
View Code
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
const int MAX = 100001;
struct Edge
{
int end; int dis;
Edge(int e,int d): end(e),dis(d) {}
};
struct Quer
{
int v; int count;
Quer(int vv,int c): v(vv),count(c) {}
};
vector<Edge> Graph[MAX];
vector<Quer> query[MAX];
bool vis[MAX];
int fa[MAX],n,q;
long long dist[MAX],ans[MAX];
void init()
{
int i;
for(i = 0;i <= n;++i)
{
Graph[i].clear();
dist[i] = 0;
fa[i] = i;
vis[i] = false;
}
for(i = 0;i <= MAX;++i) query[i].clear();
}
int Findset(int x)
{
while(fa[x] != x)
{
x = fa[x];
}
return x;
}
void Tarjan(int now,long long cur_dis)
{
int i,end,dis,v,count;
vis[now] = true; dist[now] = cur_dis; fa[now] = now;
for(i = 0;i < query[now].size();++i)
{
v = query[now][i].v; count = query[now][i].count;
if (vis[v])
{
ans[count] = dist[now]+dist[v]-2*dist[Findset(v)];
}
}
for(i = 0;i < Graph[now].size();++i)
{
end = Graph[now][i].end; dis = Graph[now][i].dis;
if(!vis[end])
{
Tarjan(end,cur_dis + dis);
fa[end] = now;
}
}
}
int main()
{
int i,u,v,d;
while(scanf("%d",&n) && n)
{
init();
for(i = 1;i < n;++i)
{
scanf("%d %d",&v,&d);
Graph[v].push_back(Edge(i,d));
Graph[i].push_back(Edge(v,d));
}
scanf("%d",&q);
for(i = 0;i < q;++i)
{
scanf("%d %d",&u,&v);
query[u].push_back(Quer(v,i));
query[v].push_back(Quer(u,i));
}
Tarjan(0,0);
for(i = 0;i < q;++i)
{
if(i) printf(" ");
cout<<ans[i];
}
printf("\n");
}
return 0;
}