• POJ1986 LCA在线算法


    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. 

    题目大意:

    农夫约翰的牛太懒了,想走一条最短的路参加马拉松.通过POJ1984http://poj.org/problem?id=1984易知该图为无环图,因此有且仅有一条路使得路径最短,寻找最近公共祖先求解即可.

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    
    using namespace std;
    const int N=4e4+10;
    int head[N], ver[2*N], depth[2*N], first[N];//N个点完全遍历需要2*N-1次,注意设置数组大小为2*N
    int dir[N], dp[2*N][20];
    bool vis[N];
    int tot;
    struct edge{
        int u,v,w,next;
    }e[2*N];
    
    void add(int u,int v,int w,int &k)//构造图形
    {
        e[k].u=u,e[k].v=v,e[k].w=w;
        e[k].next=head[u],head[u]=k++;
        swap(u,v);
        e[k].u=u,e[k].v=v,e[k].w=w;
        e[k].next=head[u],head[u]=k++;
    }
    
    void dfs(int u,int dep)//深度遍历
    {
        vis[u]=1, ver[++tot]=u;
        first[u]=tot, depth[tot]=dep;
        for(int k=head[u];k!=-1;k=e[k].next)
            {
                if(!vis[e[k].v])
                    {
                        int v=e[k].v,w=e[k].w;
                        dir[v]=dir[u]+w;
                        dfs(v,dep+1);
                        ver[++tot]=u,depth[tot]=dep;
                    }
            }
    }
    
    void st(int n)
    {
        for(int i=1;i<=n;i++)
            dp[i][0]=i;//此处赋值同时储存了农场的位置
        for(int j=1;j<=20;j++)
            {
                for(int i=1;i+(1<<(j-1))-1<=n;i++)
                    {
                        int a=dp[i][j-1],b=dp[i+(1<<(j-1))][j-1];
                        depth[a]<depth[b]?dp[i][j]=a:dp[i][j]=b;//区间中深度最小的为最近公共祖先
                    }
            }
    }
    
    int rmq(int x,int y)//区间查询
    {
        int k=log2(y-x+1.0);
        int a=dp[x][k],b=dp[y-(1<<k)+1][k];
        return  depth[a]<depth[b]?a:b;
    }
    
    int LCA(int u,int v)
    {
        int x=first[u],y=first[v];//first为u,v初次出现的位置
        if(x>y) swap(x,y);
        int res=rmq(x,y);
        return ver[res];
    }
    
    int main()
    {
        int n,m,k;
        while(~scanf("%d%d",&n,&m))
            {
                int num=0;
                memset(vis,0,sizeof(vis));
                memset(head,-1,sizeof(head));
                for(int i=1;i<=m;i++)
                    {
                        int u,v,w;
                        char ch[2];
                        scanf("%d%d%d%s",&u,&v,&w,ch);
                        add(u,v,w,num);
                    }
                tot=0,dir[1]=0;
                dfs(1,1);
                st(2*n-1);
                scanf("%d",&k);
                while(k--)
                    {
                        int u,v;
                        scanf("%d%d",&u,&v);
                        int dis=LCA(u,v);
                        printf("%d
    ",dir[u]+dir[v]-2*dir[dis]);
                    }
            }
        return 0;
    }
    
  • 相关阅读:
    2073: [POI2004]PRZ
    BZOJ 3669: [Noi2014]魔法森林
    Dominator Tree & Lengauer-Tarjan Algorithm
    BZOJ 3526: [Poi2014]Card
    BZOJ 2733: [HNOI2012]永无乡
    BZOJ 2929: [Poi1999]洞穴攀行
    BZOJ 3730: 震波
    BZOJ 1778: [Usaco2010 Hol]Dotp 驱逐猪猡
    BZOJ 1195: [HNOI2006]最短母串
    BZOJ 4030: [HEOI2015]小L的白日梦
  • 原文地址:https://www.cnblogs.com/BlueDoor1999/p/13301392.html
Copyright © 2020-2023  润新知