Fork me on GitHub

poj 1984 Navigation Nightmare

http://poj.org/problem?id=1984

这里写图片描述

这是一道经典的带权并查集,每插入一个点,维护两个权值的数组,代表关于根节点的x坐标和y坐标,
记录这两个权值数组就可以了。W是x减,E是x加,N是y减,S是y加。
合并时,注意一些细节。(注意我们输入的是x和y之间的距离,记录的是ry到rx的距离,加减法要做好)

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
using namespace std;
int n,m,Q,t,dx,dy;
struct H{
    int x,y,l;
    char d;
}p[40009];
int f[40009],fx[40009],fy[40009];
int ABS(int x){return x<0?-x:x;}
int find(int x)
{
    if(x==f[x]) return x;
    int px=find(f[x]);
    fx[x]+=fx[f[x]];
    fy[x]+=fy[f[x]];
    f[x]=px; 
    return px;
}
void mix(int rx,int ry,int x,int y)//把ry并到rx上去 
{   
    fx[ry]=fx[x]+dx-fx[y];
    fy[ry]=fy[x]+dy-fy[y];
    f[ry]=rx;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].l);
        cin>>p[i].d;
    }

    scanf("%d",&Q);
    t=1;
    while(Q--)
    {
        int x,y,T;
        scanf("%d%d%d",&x,&y,&T);
        while(t<=T)
        {
            int xx=find(p[t].x);
            int yy=find(p[t].y);
            dx=0,dy=0;
            if(xx==yy) continue;
            if(p[t].d=='E') dx+=p[t].l;
            if(p[t].d=='W') dx-=p[t].l;
            if(p[t].d=='N') dy-=p[t].l;
            if(p[t].d=='S') dy+=p[t].l;
            mix(xx,yy,p[t].x,p[t].y);
            t++;
        }
        int X=find(x),Y=find(y);
        if(X!=Y) printf("-1\n");
        else printf("%d\n",ABS(fx[x]-fx[y])+ABS(fy[x]-fy[y]));
    }
    return 0;
}
posted @ 2017-09-24 17:48  primes  阅读(156)  评论(0编辑  收藏  举报