POJ 1984 Navigation Nightmare(路径压缩并查集)
http://poj.org/problem?id=1984
题意:
有N个点在二维平面上,但是不直接给你他们的坐标,而是给你M条A B L D 语句表示从A到B有长为L的(方向为朝上或下或左或右的)直线。现在给你K个A B I 这样的询问,表示你需要回答在添加完上面前I条直线那一刻时,从A与B的曼哈顿距离(该值为|XA-XB|+|YA-YB|).
分析:
首先本题应该先读入所有询问,然后按I从小到大离线处理每个询问的(代码中并未离线处理,因为本题测试数据的I就是默认从小到大增加的)。
令最左上角的坐标为(0,0)且当往右走时x坐标增大,往下走时y坐标增大。x为横坐标,y为纵坐标。定义并查集,令fa[i]表示i的父节点编号,X[i]与Y[i]表示从i走到它的父节点需要走多少X正方向与Y正方向的距离。
所以对于在同一个连通分量的两个点A与B,我们才能算出他们的曼哈顿距离。如果不在同一个分量,那么两个点的相对坐标不知道,自然不能算曼哈顿距离了。
比如第一句输入为 1 2 3 N 表示从1点朝北方向长3的路可以到2点,那么2的父亲就是1点,且x[2]=0,y[2]=-3,即2点的x坐标加0,y坐标加-3就是其父节点1点的x坐标和y坐标。
AC代码:157ms
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=40000+100;
const int UP=0,DOWN=1,LEFT=2,RIGHT=3;//上下左右 对应 北 南 西 东
const int dx[]= {0,0,-1,1};
const int dy[]= {-1,1,0,0};
int F[MAXN];//根
int x[MAXN];//x[i]=3,根的x坐标减i节点的x坐标之差为3
int y[MAXN];//同x
int n,m,k;
int road_1[MAXN],road_2[MAXN],road_3[MAXN],road_4[MAXN];//分别存输入路的4个变量
int findset(int i)
{
if(F[i]==-1)return i;
int temp = findset(F[i]);
x[i] +=x[F[i]];//路径压缩成i到根的坐标差
y[i] +=y[F[i]];
return F[i]=temp;
}
void bind(int i,int j,int L,int D)//L为合并的路长,D为路的方向,合并的是i和j的根
{
int fa = findset(i);
int fb = findset(j);
if(fa!=fb)//自己画个图推理一下,设i点的坐标为(0,0),然后推出j,fa,fb的坐标及相对关系
{
F[fa]=fb;
x[fa] = L*dx[D]+x[j]-x[i];
y[fa] = L*dy[D]+y[j]-y[i];
}
}
int main()
{
while(scanf("%d%d",&n,&m)==2)
{
memset(F,-1,sizeof(F));
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
for(int i=1; i<=m; i++)
{
char str[10];
scanf("%d%d%d%s",&road_1[i],&road_2[i],&road_3[i],str);
switch(str[0])
{
case 'N':
road_4[i]=0;
break;
case 'S':
road_4[i]=1;
break;
case 'W':
road_4[i]=2;
break;
case 'E':
road_4[i]=3;
break;
}
}
scanf("%d",&k);
int i=0;//指针,保存当前处理到第几条road记录了,别忘了i要增长
while(k--)//开始一条一条处理询问了
{
int u,v,time;
scanf("%d%d%d",&u,&v,&time);
for(int j=i+1; j<=time; j++)
{
int a,b,L,D;
a=road_1[j];
b=road_2[j];
L=road_3[j];
D=road_4[j];
bind(a,b,L,D);//此处要合并a连通分量和b连通分量的根
}
int fu=findset(u);
int fv=findset(v);
if(fu!=fv)//不同连通分量
printf("-1\n");
else//相同连通分量
{
int dist = abs(x[u]-x[v])+abs(y[u]-y[v]);
printf("%d\n",dist);
}
i=time;//注意
}
}
return 0;
}
<span style="font-family:Arial, Helvetica, sans-serif;"><span style="white-space: normal;">
</span></span>