zoukankan      html  css  js  c++  java
  • cogs 1588. [USACO Feb04]距离咨询 倍增LCA

    1588. [USACO Feb04]距离咨询

    ★★   输入文件:dquery.in   输出文件:dquery.out   简单对比
    时间限制:1 s   内存限制:256 MB

    【题目描述】

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

    每个农场最多能在东西南北四个方向连结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的距离。

    【来源】

    Brian Dean,2004

    USACO 2004 February Contest Green Problem 3 Distance Queries

    Translate by: 庄乐

    天啊 这一道题看起来好难的样子呢  杂么办呢?

    唉 谁知道呢

    想法一:非常不现实 跑最短路 很显然不超时才怪呢

    想法二:呵呵 今天学的 倍增LCA 求最近公共祖先

    所以这和这道题到底有什毛关系

    。。。。。。。。

    首先最短路中不是整了一个dis数组 表示根节点到当前节点的距离吗

    所以。。。。。。

    首先想法一之所以不可行 是因为还要询问K次(<=10000)所以就是跑最短路的次数未免也太多了

    所以。。就是先把dis数组与处理出来  那么只要选定一个点 作为根   然后跑一个dfs遍历一遍 记录dis值   

    哈哈~想了半天 但是dis数组是计算根节点到i点的距离啊

    跟这一题求两点ab之间的距离有啥关系。。。。

     倍增LCA是求最近公共祖先

    也就是说从最近公共祖先到根节点那一块 是a到根节点路径  和 b到根节点路径  重合的那一部分

    停!!++++想出正解了

    也就是说   两点之间的距离就是 dis [ a ] +dis [ b ] - 2 * dis [ lca( a,b ) ]

    想一想其实也很简单   就是a到根节点的距离-dis [ lca( a,b ) ] 就是a到最近公共祖先的距离

    b的也是一样   那么分别求出两点到最近公共祖先的距离 拼起来就是两点之间的距离拉

    哈哈 我们再来细化一下代码的具体实现细节

    首先我们要建一棵树 假如1号节点是根节点吧  

    然后一大堆输入嗯嗯嗯

    先跑一个dfs 从根节点开始把dis数组求一遍

    然后每输入 a b两个点  就直接出答案了~~~~~呵呵呵 真的有这么简单吗 ?? 试试看吧

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,Root=1;
    const int maxn=40005;
    struct edge{
        int to,val;
    };
    vector<edge> e[maxn];
    int dis[maxn],fa[21][maxn],Depth[maxn],vis[maxn];
    void Addedge(int x,int y,int z){
        edge tmp;tmp.to=y;tmp.val=z;
        e[x].push_back(tmp);
        tmp.to=x;e[y].push_back(tmp);//这是一个双向边 
    }
    void Dfs_dis_set(int rt){
        if(rt>n) return;
        for(int i=0;i<e[rt].size();i++){
            int y=e[rt][i].to;
            if(vis[y])continue;
            vis[y]=1;
            dis[y]=dis[rt]+e[rt][i].val;
            Depth[y]=Depth[rt]+1;
            Dfs_dis_set(y);
        }//初始化dis数组 和Depth数组 
    }
    void Dfs_fa_set(int p){
        for(int i=1;i<=20;++i)
            fa[i][p]=fa[i-1][fa[i-1][p]];
        for(int i=0;i<e[p].size();i++)
            if(e[p][i].to!=fa[0][p])
                fa[0][e[p][i].to]=p,Dfs_fa_set(e[p][i].to);
    }
    int lca(int x,int y){
        if(Depth[x]<Depth[y]) swap(x,y);
        int res=Depth[x]-Depth[y];
        for(int k=20;k>=0;k--)
            if((1<<k)<=res)x=fa[k][x],res-=1<<k;
        if(x==y)return x;
        for(int k=20;k>=0;k--){
            if(fa[k][x]!=fa[k][y])
                x=fa[k][x],y=fa[k][y];
        }
        return fa[0][x];
    }
    int main()
    {
        freopen("dquery.in","r",stdin);freopen("dquery.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            int x,y,z;char c;
            cin>>x>>y>>z>>c;
            Addedge(x,y,z);//读入,建边 
        }
        dis[1]=0;Depth[1]=0;vis[1]=1;
        Dfs_dis_set(1);
        
        //fa[0][1]=1;
        for(int i=0;i<=20;i++) fa[i][1]=1;//这一行非常迷
        Dfs_fa_set(1);
        int k;scanf("%d",&k);
        while(k--){
            int a,b;scanf("%d%d",&a,&b);
            printf("%d
    ",dis[a]+dis[b]-2*dis[lca(a,b)]);
        //    cout<<lca(a,b)<<endl;
        }
        return 0;
    }
  • 相关阅读:
    Java Formatter 阅读心得
    Android 应用的动画实践View Animation篇
    Hexo 简明入门教程(一)
    用Gradle 构建你的android程序依赖管理篇
    MQTT 折腾笔记协议简读
    ingress 在中国大众篇
    谈谈常见的移动应用设计风格
    用nodejs 改造一个移动版本的网站
    Android AdapterView 源码分析以及其相关回收机制的分析
    关于计算机类课程实验教学的思考
  • 原文地址:https://www.cnblogs.com/Tidoblogs/p/11312189.html
Copyright © 2011-2022 走看看