POJ 1984

QAQ
这道题调了一节课,,,,,
一个比较水的带权并查集
dx[i]为到i到根节点的距离(横坐标),dy[i]为纵坐标
找两个点的曼哈顿距离,我们可以根据两个点距离根节点的距离间接推出
然后这是个离线算法,先把操作记录下来,然后由于时间递增,可以在讯问时进行合并

#include <cstdio>
#include <iostream> 
using namespace std;
struct tw{
    int fat;
    int dx;
    int dy;
};
tw w[99999];
char get[99999][50];  
int abs(int k)
{
    if(k<0) return -k;
    return k;
}
int find(int nd)  
{  
    if(nd==w[nd].fat)  
        return nd;  
    int tmp=w[nd].fat;  
    w[nd].fat=find(w[nd].fat);  
    w[nd].dx+=w[tmp].dx;  
    w[nd].dy+=w[tmp].dy;  
    return w[nd].fat;  
}  
void Union(int a, int b, int dx, int dy)  
{  
    int r1=find(a);  
    int r2=find(b);
    if(r1!=r2)  
    {  
        w[r2].fat=r1;  
        w[r2].dx=w[a].dx+dx-w[b].dx;  
        w[r2].dy=w[a].dy+dy-w[b].dy;   
    }  
}  
int main()
{
    int n,m;

    scanf("%d%d",&n,&m);
    getchar();  
    for(int i=1;i<=n;i++)
     w[i].fat=i,w[i].dx=w[i].dy=0;

    for(int i=0;i<m;i++)  
     gets(get[i]);  

    int t;
    scanf("%d",&t);
    int last_time=0;
    for(int i=1;i<=t;i++)
     {
        int d1,d2,time;
        scanf("%d%d%d",&d1,&d2,&time);

        for(int i=last_time;i<time;i++)  
        {  
            int dx=0,dy=0;  
            int a,b,d;
            char dir[2];  
            sscanf(get[i], "%d %d %d %s", &a, &b, &d, dir);  
            switch(dir[0])  
            {  
                case'E':dx += d; break;  
                case 'W': dx -= d; break;  
                case 'N': dy += d; break;  
                case 'S': dy -= d; break;  
            }  
            Union(a, b, dx, dy);  
        }  
        last_time = time;

        int q1=find(d1);
        int q2=find(d2);
        if(q1!=q2)
         printf("-1\n");
        else
         printf("%d\n",abs(w[d1].dx-w[d2].dx)+abs(w[d1].dy-w[d2].dy));
     }
     return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值