poj 1968 Distance Queries LCA Tarjan 离线算法

来源:互联网 发布:淘宝总部投诉电话 编辑:程序博客网 时间:2024/05/25 12:20

链接: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 0x7ffffffftypedef 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]);    }}


0 0
原创粉丝点击