参考博客:https://blog.csdn.net/qq_41874469/article/details/80329447
题意:有n个点位于一平面上,现给出m条关系(给出的关系有时间上的顺序,每秒给一条)u v w ch 。(ch是方向)表示v在u的 东/南/西/北 w米。再给出k次查询,每次查询给出两个点a,b,以及一个时间t,表示在时间t的时候查询a到b的距离并输出。查询不到,就输-1。(两点之间的距离是曼哈顿距离)
思路:带权并查集,两个权值,分别记录子节点到根节点的水平方向的距离和竖直方向的距离。因为查询的时间有可能在合并的时间前面,所以要先记下所有的数据!
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=4e4+5;
struct node{
int fa,east,south;
}p[maxn];
int n,m,T;
int u[maxn],v[maxn],w[maxn];
char pos[maxn];
int ans[maxn];
struct Node{
int a,b,t,index;
bool operator < (const Node& f)const {
return t<f.t;
}
}q[maxn];
void init(){
T=1;
for(int i=1;i<=n;i++){
p[i].fa=i;
p[i].east=p[i].south=0;
}
}
int find(int x){
if(x==p[x].fa) return x;
int tmp=p[x].fa;
p[x].fa=find(tmp);
p[x].east+=p[tmp].east;
p[x].south+=p[tmp].south;
return p[x].fa;
}
void unite(int x,int y,int w,char px){
int r1=find(x);
int r2=find(y);
int e=0,s=0;
if(px=='N') s=-w;
else if(px=='S') s=w;
else if(px=='W') e=-w;
else e=w;
if(r1!=r2){
p[r2].fa=r1;
p[r2].east=p[x].east-e-p[y].east;
p[r2].south=p[x].south-s-p[y].south;
}
}
void check(int t){
int x=q[t].a;
int y=q[t].b;
int r1=find(x);
int r2=find(y);
if(r1!=r2){
ans[q[t].index]=-1;
}else{
ans[q[t].index]=abs(p[x].east-p[y].east)+abs(p[x].south-p[y].south);
}
T++;
}
int main(){
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=m;i++){
scanf("%d%d%d %c",&u[i],&v[i],&w[i],&pos[i]);
}
int k;
scanf("%d",&k);
for(int i=1;i<=k;i++){
scanf("%d%d%d",&q[i].a,&q[i].b,&q[i].t);
q[i].index=i;
}
sort(q+1,q+1+k);
for(int i=1;i<=m;i++){
unite(u[i],v[i],w[i],pos[i]);
while(q[T].t==i&&T<=k) check(T);
}
for(int i=1;i<=k;i++)
printf("%d\n",ans[i]);
return 0;
}