zoukankan      html  css  js  c++  java
  • Distance Queries 距离咨询 (LCA倍增模板)

    农夫约翰有N(2<=N<=40000)个农场,标号1到N。M(2<=M<=40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样,图中农场用F1..F7表示:

    image

    每个农场最多能在东西南北四个方向连结4个不同的农场。此外,农场只处在道路的两端。道路不会交叉而且每对农场间有且仅有一条路径。邻居鲍伯要约翰来导航,但约翰丢了农场的地图,他只得从电脑的备份中修复率。每一条道路的信息如下:

        从农场23往南经距离10到达农场17
    
    从农场1往东经距离7到达农场17
    
    . . .
    

    最近美国过度肥胖非常普遍。农夫约翰为了让他的奶牛多做运动,举办了奶牛马拉松。马拉松路线要尽量长。

    奶牛们拒绝跑马拉松,因为她们悠闲的生活无法承受约翰选择的如此长的赛道。因此约翰决心找一条更合理的赛道。他打算咨询你。读入地图之后会有K个问题,每个问题包括2个整数,就是约翰感兴趣的2个农场的编号,请尽快算出这2个农场间的距离。

    输入格式

    第1行:两个分开的整数N和M。

    第2到M+1行:每行包括4个分开的内容,F1,F2,L,D分别描述两个农场的编号,道路的长度,F1到F2的方向N,E,S,W。

    第2+M行:一个整数K(1<=K<=10000).

    第3+M到2+M+K行:每行输入2个整数,代表2个农场。

    输出格式

    对每个问题,输出单独的一个整数,给出正确的距离。

    样例

    样例输入

    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
    

    样例输出

    13
    3
    36
    

    样例解释

    农场2到农场6有20+3+13=36的距离


    析:LCA模板先将 x与y翻到同一深度,然后继续上翻,利用二进制


    代码如下:

    #include<bits/stdc++.h>
    #define ll long long
    #define re register int
    #define N 500100
    using namespace std;
    ll sum[N],fa[N][30],p[N][30];
    ll to[N<<1],next[N<<1],head[N<<1],w[N<<1];
    ll deep[N],dis[N];
    ll n,m,k,tot;
    ll a,b,c;
    char ch[5];
    void add(ll x,ll y,ll z)
    {
        to[++tot]=y;
        next[tot]=head[x];
        head[x]=tot;
        w[tot]=z;
    }
    void bfs(ll x,ll f)
    {
        for(re i=1;(1<<i)<=n;i++)
            fa[x][i]=fa[fa[x][i-1]][i-1];
        for(re i=head[x];i;i=next[i])
        {
            ll p=to[i];
            if(p==f)
                continue;
            deep[p]=deep[x]+1;
            dis[p]=dis[x]+w[i];
            fa[p][0]=x;
            bfs(p,x);
        }
    }
    ll lca(ll x,ll y)
    {
        if(deep[x]<deep[y])
            return lca(y,x);
        ll d=deep[x]-deep[y];
        for(re i=0;(1<<i)<=d;i++)
            if((1<<i)&d)
                x=fa[x][i];
        if(x==y)
            return x;
        for(re i=18;i>=0;i--)
            if(fa[x][i]!=fa[y][i])
            {
                x=fa[x][i];
                y=fa[y][i];
            }
        return fa[x][0];
    }
    int main()
    {
        scanf("%lld%lld",&n,&m);
        for(re i=1;i<=m;i++)
        {
            scanf("%lld%lld%lld%s",&a,&b,&c,ch);
            add(a,b,c);
            add(b,a,c);
        }
        bfs(1,0);
        scanf("%lld",&k);
        while(k--)
        {
            scanf("%lld%lld",&a,&b);
            //cout<<"dis[a]="<<dis[a]<<" dis[b]="<<dis[b]<<" dis[lca]="<<dis[lca(a,b)]<<" lca="<<lca(a,b)<<endl;
            printf("%lld\n",dis[a]+dis[b]-2*dis[lca(a,b)]);
        }
        return 0;
    }

  • 相关阅读:
    如何设计一个秒杀系统
    Leetcode题目437:路径总和III(递归-简单)
    Leetcode题目461:汉明距离(位运算-简单)
    Leetcode题目617:合并二叉树(递归-简单)
    分布式锁
    分布式搜索引擎
    数据库
    Java知识体系思维导图
    wav文件头详解,看懂wav文件
    推荐一个最近在学习的AI算法工程师手册,侵删
  • 原文地址:https://www.cnblogs.com/WindZR/p/14672839.html
Copyright © 2011-2022 走看看