带权并查集【bzoj3362】: [Usaco2004 Feb]Navigation Nightmare 导航噩梦
【bzoj】3362: [Usaco2004 Feb]Navigation Nightmare 导航噩梦
农夫约翰有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.
两点之间只有一条路径,所以这是一颗树。又因为要判断两点是否连通,可以想到用并查集维护。
又因为要维护两点之间的曼哈顿距离,所以用带权并查集维护每个点到其祖先的x距离和y距离。
带权并查集小白表示这道题让我很难受。
首先在路径压缩的时候,代码很容易写出来:
int find(int x){
if(f[x]==x)return x;
itn t=f[x];
f[x]=find(f[x]);
dx[x]+=dx[t];
dy[x]+=dy[t];
return f[x];
}
之后我们把操作排序离线。
那么对于合并的操作,我认为才是最大的难点。
首先给出代码:
while(now<=q[i].p){
int ta=find(q[i].x);int tb=find(q[i].y);
if(ta!=tb){
f[ta]=tb;
dx[ta]=dx[b[now]]+cx[now]-dx[a[now]];
dy[ta]=dy[b[now]]+cy[now]-dy[a[now]];
}
now++;
}
重点是对于dx和dy的更新。

那画个图其实就好理解了。
注意边是有方向的。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int wx=40017;
int f[wx],dx[wx],dy[wx],a[wx],b[wx],cx[wx],cy[wx],ans[wx];
int n,m,t;
char opt[5];
inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
int find(int x){
if(x==f[x])return x;
int t=f[x];
f[x]=find(f[x]);
dx[x]+=dx[t];
dy[x]+=dy[t];
return f[x];
}
struct node{
int x,y,p,id;
friend bool operator < (const node& a,const node& b)
{
return a.p<b.p;
}
}q[wx];
int main(){
n=read();read();
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<n;i++){
a[i]=read();b[i]=read();t=read();scanf("%s",opt+1);
if(opt[1]=='E')cx[i]=t;
if(opt[1]=='W')cx[i]=-t;
if(opt[1]=='N')cy[i]=t;
if(opt[1]=='S')cy[i]-=t;
}
m=read();
for(int i=1;i<=m;i++){
q[i].x=read();q[i].y=read();q[i].p=read();q[i].id=i;
}
sort(q+1,q+1+m);
int now=1;
for(int i=1;i<=m;i++){
while(now<=q[i].p){
int ta=find(a[now]);
int tb=find(b[now]);
if(ta!=tb){
f[ta]=tb;
dx[ta]=dx[b[now]]+cx[now]-dx[a[now]];
dy[ta]=dy[b[now]]+cy[now]-dy[a[now]];
}
now++;
}
int ta=find(q[i].x),tb=find(q[i].y);
ans[q[i].id]=(ta==tb?abs(dx[q[i].x]-dx[q[i].y])+abs(dy[q[i].x]-dy[q[i].y]):-1);
// now++;
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}
带权并查集【bzoj3362】: [Usaco2004 Feb]Navigation Nightmare 导航噩梦的更多相关文章
- BZOJ3362 [Usaco2004 Feb]Navigation Nightmare 导航噩梦
标题效果:自脑补. 思维:与维护两个维度和可设置为检查右. 注意,标题给予一堆关系的.我们应该加入两对关系. Code: #include <cstdio> #include <cs ...
- BZOJ_3362_[Usaco2004 Feb]Navigation Nightmare 导航噩梦_并查集
BZOJ_3362_[Usaco2004 Feb]Navigation Nightmare 导航噩梦_并查集 Description 农夫约翰有N(2≤N≤40000)个农场,标号1到N,M( ...
- BZOJ 3362: [Usaco2004 Feb]Navigation Nightmare 导航噩梦
Description 给你每个点与相邻点的距离和方向,求两点间的曼哈顿距离. \(n \leqslant 4\times 10^4\) . Sol 加权并查集. 像向量合成一样合并就可以了,找 \( ...
- bzoj3376/poj1988[Usaco2004 Open]Cube Stacking 方块游戏 — 带权并查集
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3376 题目大意: 编号为1到n的n(1≤n≤30000)个方块正放在地上.每个构成一个立方 ...
- 【BZOJ 3376】[Usaco2004 Open]Cube Stacking 方块游戏 带权并查集
这道题一开始以为是平衡树结果发现复杂度过不去,然后发现我们一直合并而且只是记录到最低的距离,那么就是带权并查集了,带权并查集的权一般是到根的距离,因为不算根要好打,不过还有一些其他的,具体的具体打. ...
- 初涉「带权并查集」&&bzoj3376: [Usaco2004 Open]Cube Stacking 方块游戏
算是挺基础的东西 Description 约翰和贝茜在玩一个方块游戏.编号为1到n的n(1≤n≤30000)个方块正放在地上.每个构成一个立方柱. 游戏开始后,约翰会给贝茜发出P(1≤P ...
- POJ 1703 Find them, Catch them(带权并查集)
传送门 Find them, Catch them Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 42463 Accep ...
- [NOIP摸你赛]Hzwer的陨石(带权并查集)
题目描述: 经过不懈的努力,Hzwer召唤了很多陨石.已知Hzwer的地图上共有n个区域,且一开始的时候第i个陨石掉在了第i个区域.有电力喷射背包的ndsf很自豪,他认为搬陨石很容易,所以他将一些区域 ...
- poj1417 带权并查集 + 背包 + 记录路径
True Liars Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 2713 Accepted: 868 Descrip ...
随机推荐
- Bootstrap-other内置组件
1.缩略图 缩略图在网站中最常用的地方就是产品列表页面,一行显示几张图片,有的在图片底下(左侧或右侧)带有标题.描述等信息.Bootstrap框架将这一部独立成一个模块组件.并通过“thumbnail ...
- 如果你使用WebView+FloatingActionButton
在WebView中想要使用FAB,如果你想向上滑动的时候隐藏FAB,那么需要再WebView外面套一个ScrollView! 原因之前也分析过,和为什么ListView不能让ToolBar.Tab隐藏 ...
- poj2395
#include<iostream> #include<cstdio> #include<algorithm> #include<cstdlib> ...
- mouseout与mouseleave的区别
1 mouseout:当鼠标指针从元素上移开时,发生 mouseout 事件.该事件大多数时候会与 mouseover 事件一起使用. 2 mouseout与 mouseleave 事件不同,不论鼠标 ...
- NSDictionary和NSArray
// 字典里套数组 NSArray *array1 = @[@"huahau" , @"hehe"]; NSArray *array2 = @[@"x ...
- NSDictionary 用法
//Dictionary //不可变 //字典里面:是以键值对存放的 //字典存放顺序是无序的 //字典里面:value可以重复,但key不能重复 //字典里面:key一般用字符串表示,value可用 ...
- linux下dns设置详解
DNS就是Domain Name System,它能够把形如www.21php.com这样的域名转换为211.152.50.35这样的IP地址;没有DNS,浏览21php.com这个网站时,就必须用2 ...
- Python-连接Redis并操作
首先开启redis的外连 sch01ar@ubuntu:~$ sudo vim /etc/redis/redis.conf 把bind 127.0.0.1这行注释掉 然后重启redis sudo /e ...
- 奇异值分解(SVD)详解
2012-04-10 17:38 45524人阅读 评论(18) 收藏 举报 分类: 数学之美 版权声明:本文为博主原创文章,未经博主允许不得转载. SVD分解 SVD分解是LSA的数学基础,本文是 ...
- linux命令-vim一般模式下复制剪切粘贴
删除光标后的一个字符 x 删除光标前的一个字符 shift+x 删除指定个数的字符 数字+x 删除一行字符 dd 剪切指定行数 数字dd 3dd 剪切3行 其实并没有删掉而是保存着剪切板里 粘贴在 ...
.jpg)