您的位置:首页 > 产品设计 > UI/UE

poj 1968 Distance Queries LCA Tarjan 离线算法

2014-02-12 14:10 453 查看
链接:http://poj.org/problem?id=1986

算法概述:所谓离线,就是把所有要求公共祖先的结点对用邻接表存起来,输入完毕后一起计算。

算法实现不困难,就是并查集和DFS。

从根开始遍历,遍历到新的结点时将该点记录为根(H[u]=u),建立以这个点为根的集合。对这个集合的每个子树进行搜索,即将子树内部的存在的所有LCA询问解决。当搜索到LCA的一个点,另外一个点被询问过了,最近公共祖先就是另外一个点此时的根。如果有子树中LCA没有解决,则其LCA询问不在这个根的子树内,将该子树所有点的根记录为u。由于是递归实现,则保证最先找到的最近的祖先。看代码显而易见。

题意:给N个农场,给出M对农场之间的距离。计算K对农场的距离。

思路:是一道标准的模板题。数据量到不能用最短路算,所以用LCA。记录从根到每个点之间的深度,答案就是ans[i]=d[query[i].v]+d[u]-2*d[findset(query[i].v)]。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<ctype.h>
#include<algorithm>
#include<string>
#define PI acos(-1.0)
#define maxn 100005
#define INF 1<<25
#define MAX 0x7fffffff
typedef long long ll;
using namespace std;
struct Edge
{
int v,w;
int next;
} edge[maxn],query[maxn];
int ans[maxn],point[maxn],head[maxn],d[maxn],aa[maxn],H[maxn],vv[maxn],tot,tt;;
int e_top,q_top;
int init()
{
e_top=q_top=0;
memset(vv,0,sizeof(vv));
memset(head,-1,sizeof(head));
memset(aa,0,sizeof(aa));
memset(point,-1,sizeof(point));
memset(ans,0,sizeof(ans));
memset(d,0,sizeof(d));
memset(H,0,sizeof(H));
}
int add_edge(int u,int v,int w)
{
edge[e_top].v=v;
edge[e_top].w=w;
edge[e_top].next=head[u];
head[u]=e_top++;
edge[e_top].v=u;
edge[e_top].w=w;
edge[e_top].next=head[v];
head[v]=e_top++;
}
int add_query(int u,int v)
{
query[q_top].v=v;
query[q_top].next=point[u];
point[u]=q_top++;
query[q_top].v=u;
query[q_top].next=point[v];
point[v]=q_top++;
}
int findset(int x)
{
return x==H[x]?x:H[x]=findset(H[x]);
}
int dfs(int u,int w)
{
d[u]=w,H[u]=u;
vv[u]=1;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
if(!vv[edge[i].v])
{
dfs(edge[i].v,w+edge[i].w);
H[edge[i].v]=u;
}
}
for(int i=point[u];i!=-1;i=query[i].next)
{
if(vv[query[i].v])
ans[i]=d[query[i].v]+d[u]-2*d[findset(query[i].v)];
}
}
int main()
{
scanf("%d%d",&tot,&tt);
init();
for(int i=0;i<tt;i++)
{
int x,y,z;
char ss[2];
scanf("%d%d%d%s",&x,&y,&z,ss);
add_edge(x,y,z);
}
scanf("%d",&tt);
for(int i=0;i<tt;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add_query(x,y);
}
dfs(1,0);
for(int i=0;i<tt*2;i+=2)
{
if(ans[i]==0)
printf("%d\n",ans[i+1]);
else
printf("%d\n",ans[i]);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  LCA Tarjan 图论