POJ 1984 Navigation Nightmare(并查集坐标偏移)#by zh

这道题是一个并查集的高级应用,给你一些点之间的相对位置,然后有一些询问,询问的结果是返回两个点之间的曼哈顿距离。首先就要把所有数据都读入,再进行离线查询。因为查询时要求在上面的某一个关系之前,所以要把查询进行排序,记录结果的时候要保证以原来的顺序进行记录。针对排序后的查询,把符合要求的关系都加进去,就是把查询一下这两个点是否在一个集合中,如果在就不用再加了,如果不在那么就进行合并,顺便进行坐标偏移。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
map<char,int> direction;
struct Node
{
    int x,y,rt;
}p[40005];
struct Edge
{
    int t1,t2,dir,len;
}edge[40005];
struct Query
{
    int t1,t2,num,id;
}query[10005];
int ans[10005];
int n,m;
bool cmp(Query a,Query b)
{
    if(a.num!=b.num)
        return a.num<b.num;
    else return a.id<b.id;
}
Node find(int k)
{
    if(p[k].rt==k)
    {
        return p[k];
    }
    Node fa=find(p[k].rt);
    p[k].x+=fa.x;
    p[k].y+=fa.y;
    p[k].rt=fa.rt;
    return p[k];
}
int main()
{
    //freopen("input.txt","r",stdin);
    direction['E']=0;
    direction['N']=1;
    direction['W']=2;
    direction['S']=3;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        p[i].x=p[i].y=0;
        p[i].rt=i;
    }
    char d[2];
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d%s",&edge[i].t1,&edge[i].t2,&edge[i].len,d);
        edge[i].dir=direction[d[0]];
    }
    int q;
    scanf("%d",&q);
    for(int i=0;i<q;i++)
    {
        scanf("%d%d%d",&query[i].t1,&query[i].t2,&query[i].num);
        query[i].id=i;
    }
    sort(query,query+q,cmp);
    int j=0;
    for(int i=0;i<q;i++)
    {
        while(j+1<=query[i].num)
        {
            int x=edge[j].t1,y=edge[j].t2;
            Node t1=find(x),t2=find(y);
            if(t1.rt!=t2.rt)
            {
                p[t2.rt].x=t1.x-t2.x+dx[edge[j].dir]*edge[j].len;
                p[t2.rt].y=t1.y-t2.y+dy[edge[j].dir]*edge[j].len;
                p[t2.rt].rt=t1.rt;
            }
            j++;
        }
        Node x=find(query[i].t1),y=find(query[i].t2);
        if(x.rt!=y.rt)
            ans[query[i].id]=-1;
        else ans[query[i].id]=abs(x.x-y.x)+abs(x.y-y.y);
    }
    //cout<<"ok"<<endl;
    for(int i=0;i<q;i++)
        printf("%d\n",ans[i]);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值