这道题是一个并查集的高级应用,给你一些点之间的相对位置,然后有一些询问,询问的结果是返回两个点之间的曼哈顿距离。首先就要把所有数据都读入,再进行离线查询。因为查询时要求在上面的某一个关系之前,所以要把查询进行排序,记录结果的时候要保证以原来的顺序进行记录。针对排序后的查询,把符合要求的关系都加进去,就是把查询一下这两个点是否在一个集合中,如果在就不用再加了,如果不在那么就进行合并,顺便进行坐标偏移。
#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]);
}