POJ1984 Navigation Nightmare(并查集)

来源:互联网 发布:学编程从什么开始学 编辑:程序博客网 时间:2024/06/03 19:30

    题意:有N个农场,连接这些农场的路只有水平的和竖直的。给出M条信息(f1 f2 L D),说明f2在f1的D方向L距离处。给出k次查询(f1 f2 index),意为根据给出的前index条信息,f1和f2的最短距离是否能确定,可以的话就输出最短距离,否则输出-1.显然这里的最短距离是横、纵方向的最短距离之和。


    思路:显然题目需要多次判断是否属于同一集合,要用并查集。将平面看作二维直角坐标系,这样每个节点只需保存父节点值和到父节点的x、y轴距离。开始偷懒没有路径压缩果断TLE,无奈的加上T_T。找到根节点后压缩路径时需要多维护一个当前累计偏移量,用于更新当前点关于根节点的偏移。任意两点之间可以看作一个向量,画个图就明白了。


#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<algorithm>using namespace std;typedef long long ll;const int inf = 0x3f3f3f3f;const int mod = 1000000007;const int maxn = 40005;struct query{    int a,b,ind,pos;    bool operator < (const query &b)const{        return ind < b.ind;    }}qry[10005];//记录k次查询struct node{    int x,y,fa;}farm[maxn];//farm[i]记录第i个点的父节点和到父节点的距离struct relation{    int a,b,dis;    char ch;}rel[maxn];//记录输入的位置关系int n,m,k,ans[10005];int find(int cur, int &x, int &y){    int tmp, _cur = cur, dx = 0, dy = 0, tmpx, tmpy;    while(cur != farm[cur].fa){        x += farm[cur].x;        y += farm[cur].y;        cur = farm[cur].fa;    }    /*tmp、tmpx、tmpy临时变量    dx、dy记录路径压缩到当前点时从初始点累计到当前点的偏移    用初始点到根节点的总偏移x、y减去dx、dy就可以得到终点相对当前点的偏移啦    */    while(_cur != cur){        tmpx = x - dx;        tmpy = y - dy;        dx += farm[_cur].x;        dy += farm[_cur].y;        farm[_cur].x = tmpx;        farm[_cur].y = tmpy;        tmp = _cur;        _cur = farm[_cur].fa;        farm[tmp].fa = cur;    }    return cur;}int main(){    int x1,x2,y1,y2,dx,dy;    char dic;    while(~scanf("%d%d", &n, &m)){        for(int i=1; i<=n; ++i){            farm[i].fa = i;            farm[i].x = farm[i].y = 0;        }        for(int i=1; i<=m; ++i){            scanf("%d%d%d %c", &rel[i].a, &rel[i].b, &rel[i].dis, &rel[i].ch);            getchar();        }        scanf("%d", &k);        for(int i=1; i<=k; ++i){            scanf("%d%d%d", &qry[i].a, &qry[i].b, &qry[i].ind);            qry[i].pos = i;        }        sort(qry + 1, qry + k + 1);//按index排序        for(int i=1, j=1; i<=k; ++i){            for(; j<=qry[i].ind; ++j){                x1 = x2 = y1 = y2 = dx = dy = 0;                if(rel[j].ch == 'N') dy = rel[j].dis;                if(rel[j].ch == 'S') dy = -rel[j].dis;                if(rel[j].ch == 'W') dx = -rel[j].dis;                if(rel[j].ch == 'E') dx = rel[j].dis;                int fa = find(rel[j].a, x1, y1);                int fb = find(rel[j].b, x2, y2);                if(fa != fb){//合并结点时不仅要更新父节点值,还要更新x、y                    farm[fa].fa = fb;                    farm[fa].x = dx + x2 -x1;                    farm[fa].y = dy + y2 -y1;                }            }            x1 = x2 = y1 = y2 = 0;            int fa = find(qry[i].a, x1, y1);            int fb = find(qry[i].b, x2, y2);            if(fa != fb){                ans[qry[i].pos] = -1;            } else {                ans[qry[i].pos] = abs(x1 - x2) + abs(y1 - y2);            }        }        for(int i=1; i<=k; ++i){            printf("%d\n", ans[i]);        }    }    return 0;}


原创粉丝点击