POJ1986 Distance Queries【最近公共祖先】【Tarjan-LCA算法】

Distance Queries
Time Limit: 2000MS Memory Limit: 30000K
Total Submissions: 9777Accepted: 3425
Case Time Limit: 1000MS

Description


Farmer John's cows refused to run in his marathon since he chose a path much too long for their leisurely lifestyle. He therefore wants to find a path of a more reasonable length. The input to this problem consists of the same input as in "Navigation Nightmare",followed by a line containing a single integer K, followed by K "distance queries". Each distance query is a line of input containing two integers, giving the numbers of two farms between which FJ is interested in computing distance (measured in the length of the roads along the path between the two farms). Please answer FJ's distance queries as quickly as possible! 


Input
* Lines 1..1+M: Same format as "Navigation Nightmare" 

* Line 2+M: A single integer, K. 1 <= K <= 10,000 

* Lines 3+M..2+M+K: Each line corresponds to a distance query and contains the indices of two farms. 


Output

* Lines 1..K: For each distance query, output on a single line an integer giving the appropriate distance. 


Sample Input
7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
3
1 6
1 4

2 6


Sample Output
13
3

36


Hint

Farms 2 and 6 are 20+3+13=36 apart. 


Source

USACO 2004 February


题目大意:John是一个农场主,他的牛很懒,拒绝按照John选的路走。John不得不找一条

最短的路。这道题的输入前半部分和POJ1984"Navigation Nightmare"相同。在每组数据

之后是一个整数K,接下来K行是询问(u,v)的曼哈顿距离(u,v是农场编号)。最后输出所有

询问结果。

POJ1984链接:http://poj.org/problem?id=1984

思路:本题输入有些特殊,给出的是某点在某点的某个方向(东西南北)有多远。由于输入数

据比较特殊。全部是有向边,且构不成回路,所以一定会是一棵树。所以可以根据直接套用

Tarjan-LCA算法的模板,考虑树上每对节点的最短路径计算。如果确定根为1,则有

Dist(u,v) = Dist(1,u) + Dist(1,v) - 2*Dist( 1,LCA(u,v) )。先深搜一次遍历求出每个

节点到根结点的距离,再做一次LCA,就可以得出结果了。


#include
#include
#include
#include
using namespace std;
const int MAXN = 80080;
const int MAXQ = 20020;

int father[MAXN],Head[MAXN],QHead[MAXN],Dist[MAXN];

struct EdgeNode
{
    int to;
    int next;
    int lca;
}Edges[MAXN];

EdgeNode QEdges[MAXN];

int find(int x)
{
    if(x != father[x])
        father[x] = find(father[x]);
    return father[x];
}

bool vis[MAXN];

void LCA(int u)
{
    father[u] = u;
    vis[u] = true;
    for(int k = Head[u]; k != -1; k = Edges[k].next)
    {
        if(!vis[Edges[k].to])
        {
            Dist[Edges[k].to] = Dist[u] + Edges[k].lca;
            LCA(Edges[k].to);
            father[Edges[k].to] = u;
        }
    }

    for(int k = QHead[u]; k != -1; k = QEdges[k].next)
    {
        if(vis[QEdges[k].to])
        {
            //QEdges[k].lca = find(QEdges[k].to);
            QEdges[k].lca = Dist[u] + Dist[QEdges[k].to] - 2*Dist[find(QEdges[k].to)];
            QEdges[k^1].lca = QEdges[k].lca;
        }
    }
}

int main()
{
    int N,M,K,u,v,w,a,b;
    char s;
    while(~scanf("%d%d",&N,&M))
    {
        memset(father,0,sizeof(father));
        memset(Head,-1,sizeof(Head));
        memset(QHead,-1,sizeof(QHead));
        memset(vis,false,sizeof(vis));
        memset(Edges,0,sizeof(Edges));
        memset(QEdges,0,sizeof(QEdges));
        memset(Dist,0,sizeof(Dist));
        int id = 0;
        for(int i = 0; i < M; ++i)
        {
            scanf("%d%d%d %c",&u,&v,&w,&s);
            Edges[id].to = v;
            Edges[id].lca = w;
            Edges[id].next = Head[u];
            Head[u] = id++;
            Edges[id].to = u;
            Edges[id].lca = w;
            Edges[id].next = Head[v];
            Head[v] = id++;
        }
        scanf("%d",&K);
        int iq = 0;
        for(int i = 0; i < K; ++i)
        {
            scanf("%d%d",&a,&b);
            QEdges[iq].to = b;
            QEdges[iq].next = QHead[a];
            QHead[a] = iq++;
            QEdges[iq].to = a;
            QEdges[iq].next = QHead[b];
            QHead[b] = iq++;
        }
        LCA(1);
        for(int i = 0; i < iq; i+=2)
            printf("%d\n",QEdges[i].lca);
    }

    return 0;
}



你可能感兴趣的:(-----,图,论,-----,最近公共祖先,并查集,ACM题解——梦想之路)