周赛第二次的题目。传说中的最近公共祖先问题(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;
}
posted on 2011-04-20 00:23  c++fans  阅读(331)  评论(0编辑  收藏  举报