题目链接
题意
n个结点,互相有横平竖直的道路连接,依次给出m条道路信息,k次询问,每次询问你,在得知前l条道路信息后,两个节点的水平距离+竖直距离是多少,无法到达输出-1
思路
带权并查集,需要离线操作把道路信息存下来,随用随处理。开两个value数组,分别设置为到父节点水平距离和竖直距离,这个距离是有正负的,对于每次查询找到同一祖先输出距离,找不到输出-1即可,详见代码
代码
#include<iostream>
#include<cstdlib>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
using namespace std;
typedef long long ll;
const int maxn=40050;
const int inf=0x3f3f3f3f;
int n,m,q;
int fa[maxn],va1[maxn],va2[maxn];//父节点,水平距离,竖直距离
struct Node{
int u,v;
int len;
char d;
}node[maxn];//道路信息
void init(){//初始化
for(int i=0;i<maxn;i++){
fa[i]=i;
va1[i]=va2[i]=0;
}
}
int find(int x){//查找
if(fa[x]==x)
return x;
int t=find(fa[x]);
va1[x]+=va1[fa[x]];//有正负,所以直接加就行了
va2[x]+=va2[fa[x]];
return fa[x]=t;
}
void unite(Node x){
int u=x.u,v=x.v,l=x.len;
int fu=find(u),fv=find(v);
char ch=x.d;
if(fu==fv)
return ;
int dx=0,dy=0;//处理道路方向问题
if(ch=='E')
dx=l;
else if(ch=='W')
dx=-l;
else if(ch=='N')
dy=l;
else
dy=-l;
fa[fu]=fa[fv];
va1[fu]=-va1[u]+va1[v]+dx;//这里建议自己画图推,说很难说清楚
va2[fu]=-va2[u]+va2[v]+dy;
}
int main(){
IOS
init();
cin>>n>>m;
for(int i=1;i<=m;i++)//记录道路
cin>>node[i].u>>node[i].v>>node[i].len>>node[i].d;
int pt=1;
cin>>q;
while(q--){
int u,v,t;
cin>>u>>v>>t;
while(pt<=t){
unite(node[pt]);
pt++;
}
int fu=find(u),fv=find(v);
if(fu!=fv)
cout<<"-1"<<endl;
else//注意距离要加上绝对值,POJ不能用万能头,我因为这个才知道abs(int)的函数原型居然是在stdlib里
cout<<abs(va1[u]-va1[v])+abs(va2[u]-va2[v])<<endl;
}
}