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;
}

 

原文地址:https://www.cnblogs.com/ckxkexing/p/8510919.html