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
");
else printf("%d
",ABS(fx[x]-fx[y])+ABS(fy[x]-fy[y]));
}
return 0;
}