bzoj 3362: [Usaco2004 Feb]Navigation Nightmare 导航噩梦(加权并查集)

3362: [Usaco2004 Feb]Navigation Nightmare 导航噩梦

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 121  Solved: 63
[ Submit][ Status][ Discuss]

Description

    农夫约翰有N(2≤N≤40000)个农场,标号1到N,M(2≤M≤40000)条的不同的垂直或水
平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样,
图中农场用F1..F7表示, 每个农场最多能在东西南北四个方向连结4个不同的农场.此外,农场只处在道路的两端.道路不会交叉且每对农场间有且仅有一条路径.邻居鲍伯要约翰来导航,但约翰丢了农场的地图,他只得从电脑的备份中修复了.每一条道路的信息如下:
从农场23往南经距离10到达农场17
从农场1往东经距离7到达农场17
    当约翰重新获得这些数据时,他有时被的鲍伯的问题打断:“农场1到农场23的曼哈顿距离是多少?”所谓在(XI,Yi)和(X2,y2)之间的“曼哈顿距离”,就是lxl - X21+lyl - y21.如果已经有足够的信息,约翰就会回答这样的问题(在上例中答案是17),否则他会诚恳地抱歉并回答-1.

Input

    第1行:两个分开的整数N和M.
    第2到M+1行:每行包括4个分开的内容,F1,F2,三,D分别描述两个农场的编号,道路的长度,F1到F2的方向N,E,S,w.
    第M+2行:一个整数,K(1≤K≤10000),表示问题个数.
    第M+3到M+K+2行:每行表示一个问题,由3部分组成:Fi,F2,,.其中Fi和F2表示两个被问及的农场.而/(1≤J≤M)表示问题提出的时刻.J为1时,表示得知信息1但未得知信息2时.

Output

    第1到K行:每行一个整数,回答问题.表示两个农场间的曼哈顿距离.不得而知则输出-1.

Sample Input

7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
3
1 6 1
1 4 3
2 6 6

Sample Output

13
-1
10

HINT

   在时刻1,约翰知道1到6的距离为13;在时刻3,1到4的距离仍然不知道;在时刻6,位置6向


北3个距离,向西7个距离于位置2,所以距离为10.


Source

[ Submit][ Status][ Discuss]


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 100003
using namespace std;
int fa[N],disx[N],disy[N],ans[N];
int n,m,q;
struct data{
	int t,x,y,l,opt,mark;
}a[N],e[N];
int cmp(data a,data b)
{
	return a.t<b.t;
}
int find(int x)
{
	if (fa[x]==x) return x;
	int t=find(fa[x]);
	disx[x]+=disx[fa[x]];
	disy[x]+=disy[fa[x]];
	fa[x]=t;
	return fa[x];
}
int main()
{
	freopen("a.in","r",stdin);
	//freopen("my.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++) 
	{
	 char s[10];
	 scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].l,s);
	 char c=getchar();
	 while (c<'A'||c>'Z') c=getchar();
	 switch(c){
	 	case 'E':a[i].mark=1;break;
	 	case 'W':a[i].mark=2;break;
	 	case 'S':a[i].mark=3;break;
	 	case 'N':a[i].mark=4;break;
	 }
	 a[i].t=i;
	 a[i].opt=0;
    }
    scanf("%d",&q);
    for (int i=1;i<=q;i++) {
    	scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].t);
    	e[i].l=i;
	}
	for (int i=1;i<=n;i++) fa[i]=i;
	sort(e+1,e+q+1,cmp); int now=1;
	for (int i=1;i<=q;i++) {
		//cout<<e[i].x<<" "<<e[i].y<<endl;
		while (now<=m&&now<=e[i].t) {
			int r1=find(a[now].x); int r2=find(a[now].y);
		//	cout<<a[now].x<<" "<<a[now].y<<"!"<<endl;
			if (r1!=r2) {	
				fa[r2]=r1; int ans=1;
				if (a[now].mark==2||a[now].mark==3) ans=-1;
				if (a[now].mark<=2) disx[r2]=disx[a[now].x]-disx[a[now].y]-ans*a[now].l,disy[r2]=disy[a[now].x]-disy[a[now].y];
				else disy[r2]=disy[a[now].x]-disy[a[now].y]-ans*a[now].l,disx[r2]=disx[a[now].x]-disx[a[now].y];
		    }
			now++; 
		}
		int r1=find(e[i].x); int r2=find(e[i].y);
		if (r1!=r2) ans[e[i].l]=-1;
		else {
			int x=disx[e[i].x]-disx[e[i].y];
			int y=disy[e[i].x]-disy[e[i].y];
			ans[e[i].l]=abs(x)+abs(y);
		}
	}
	for (int i=1;i<=q;i++) printf("%d\n",ans[i]);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值