• POJ-1984-Navigation Nightmare+带权并查集(中级


    传送门:Navigation Nightmare

    参考:1:https://www.cnblogs.com/huangfeihome/archive/2012/09/07/2675123.html

    参考:2:http://blog.csdn.net/tc_to_top/article/details/43447727

    题意:先给出一个四方形的城市地图的全部信息,

      然后在只知道前k条信息的情况下,询问a,b之间的距离,若没连通,输出-1;

    思路:

     首先,每次询问的K是按升序排列的(讨论版里神牛说的,还有就是题号很有深意);

         这道题让我对并查集有一个新的认识:根的代表性是非常强的!并查集里如果某个节点的改动会影响到整个并查集的所有节点,那么,在union_set的时候只需要改动根节点就可以了,当然,在find_set函数里要对所有节点进行更新(这相当于一种延时标记)。我们知道,find_set函数走了两条路,一条是前往根的路,一条是从跟返回的路,那么,如果发现根已经被改动,必须在从根返回的路上更新经过的所有节点。这在find_set函数里是可以实现的。

    //样例
    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
    1 4 3
    2 6 6

    模拟一遍样例,这里是执行完Find(1-7)以后的坐标
    t = 1:   x[1] = 0,   y[1] = 0 
              x[6] = 13, y[6] = 0

    t = 2:   x[1] = 0,   y[1] = 0
               x[6] = 13, y[6] = 0
               x[3] = 22, y[3] = 0

    t = 3:   x[1] = 0,   y[1] = 0
               x[6] = 13, y[6] = 0
               x[3] = 22, y[3] = 0
               x[5] = 22, y[5] = -7

    t = 4(换原点): 
               x[4] = 0,   y[4] = 0
               x[1] = 0,   y[1] = 3
               x[6] = 13, y[6] = 3
               x[3] = 22, y[3] = 3
               x[5] = 22, y[5] = -4

    t = 5(换原点):
               x[2] = 0,   y[2] = 0
               x[4] = -20,y[4] = 0
               x[1] = -20,y[1] = 3
               x[6] = -7,  y[6] = 3
               x[3] = 2,   y[3] = 3
               x[5] = 2,   y[5] = -4

    t = 6:   x[2] = 0,   y[2] = 0
               x[4] = -20,y[4] = 0
               x[1] = -20,y[1] = 3
               x[6] = -7,  y[6] = 3
               x[3] = 2,   y[3] = 3
               x[5] = 2,   y[5] = -4
               x[7] = -20,y[7] = -2

    /*
        带权并查集;
    */
    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    using namespace std;
    
    const int maxn = 40009;
    int n,m,fa[maxn],s[maxn],h[maxn];
    
    struct node{
        int a,b,len;
        char c[5];
    }mp[maxn];
    
    void init(){
        for(int i=1;i<=n;i++)
            fa[i]=i;
        memset(s,0,sizeof(s));
        memset(h,0,sizeof(h));
    }
    int ab(int x,int y)
    {
        if(x-y>0)return x-y;
        else return y-x;
    }
    int find(int x)
    {
        if(fa[x]==x)return x;
        int tmp = fa[x];
        fa[x]=find(fa[x]);
        h[x] = h[x] + h[tmp];    // 从根回来的路上更新子节点
        s[x] = s[x] + s[tmp];
        return fa[x];
    }
    
    void uni(node t,int dx,int dy)
    {
        int px = find(t.a);
        int py = find(t.b);
        if(px==py)return;
        fa[px]=py;                // 随意合并
        h[px] = h[t.b] - h[t.a] + dx;// 暂且只对根进行偏移
        s[px] = s[t.b] - s[t.a] + dy; 
    }
    int main(){
        scanf("%d%d",&n,&m);
        init();
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d%s",&mp[i].a, &mp[i].b, &mp[i].len, mp[i].c);
        }
        int q,k=0;
        scanf("%d",&q);
        while(q--)
        {
            int l,r,e;
            scanf("%d%d%d",&l,&r,&e);
             for(int i=k;i<e;i++)
             {
                 int dx=0,dy=0;
                 switch(mp[i].c[0])
                 {
                     case 'N':dy+=mp[i].len;break;
                     case 'S':dy-=mp[i].len;break;
                     case 'E':dx+=mp[i].len;break;
                     case 'W':dx-=mp[i].len;break;
                 }
                 uni(mp[i],dx,dy);
             }
             k=e;
             int pl=find(l),pr=find(r);
             if(pl!=pr)
             {
                 puts("-1");
             }
             else 
             {
                 printf("%d
    ",ab(h[l],h[r])+ab(s[l],s[r]));
             }
        }
        return 0;
    }

     

  • 相关阅读:
    批量修改文件名
    查看数据库版本及当前登录用户是什么?
    安装mysql5.5时候的报错解决办法:
    mysql.sock的作用
    Linux系统编程15_C函数总结
    Linux系统编程14_信号和进程状态
    Linux系统编程13_CoreDump
    Linux系统编程12_标准库和POSIX标准头文件
    gcc使用
    http长链接短链接
  • 原文地址:https://www.cnblogs.com/ckxkexing/p/8510919.html
Copyright © 2020-2023  润新知