POJ - 1984 Navigation Nightmare 带俩权的并查集

题目链接

POJ-1984

题意

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;
		}
	}

猜你喜欢

转载自blog.csdn.net/TheSunspot/article/details/108045822