带权并查集
题目大义:给你n个点,再给你m条垂直或水平的边,每条边分别连着两个点,接下来会有k个询问,每个询问包含三个数据:
u
,
v
,
I
u,v,I
u,v,I,表示在 第I条边输入后能不能将u,v之间的距离计算出来,如果可以计算,就输出u,v之间的曼哈顿距离:
∣
x
1
−
x
2
∣
+
∣
y
1
−
y
2
∣
|x1-x2|+|y1-y2|
∣x1−x2∣+∣y1−y2∣,否则就输出:-1.可见,如果当前询问的两个点有关系就可以计算出来,那该如何快速判断这两个点有关系呢,因此我们想到并查集,其中边就代表着这两个点有关系,又考虑到本题的询问的I值可能会杂乱无章,耗费时间,因此我们可以将询问进行离线操作.
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
const int maxn=40005;
int n,m,k;
struct node{
int u,v,length;
char s;
}q[maxn];//存储输入的边
struct result{
int ans,pos;
}e[maxn];//存储结果
bool cmp(result a,result b)
{
return a.pos<b.pos;//将离线后的结果恢复到原来的询问次序
}
struct question{
int u,v,index,pos;
friend bool operator<(question a,question b){
return a.index<b.index;
}//重载<
}w[maxn];
struct gather{
int x,y,pre;
}g[maxn];//存储每个点的坐标和它的父节点
void init()
{
for(int i=0;i<=maxn;i++){
g[i].pre=i;
g[i].x=0;
g[i].y=0;
}//初始化每个节点的父节点都是自己,坐标都设置为原点,你也可以设置为其它
}
int finds(int x)
{
if(x==g[x].pre)return x;
int temp=g[x].pre;
g[x].pre=finds(g[x].pre);
g[x].x+=g[temp].x;
g[x].y+=g[temp].y;
return g[x].pre;
}//带权并查集的路径压缩,不要搞错语句的次序
void join(int u,int v,int length,char s)
{
int fx=finds(u),fy=finds(v);
if(fx!=fy){
g[fx].pre=fy;
if(s=='N')g[fx].y=g[v].y+length-g[u].y,g[fx].x=g[v].x-g[u].x;//可以画个图理解一下
else
if(s=='S')g[fx].y=g[v].y-length-g[u].y,g[fx].x=g[v].x-g[u].x;
else
if(s=='E')g[fx].x=g[v].x+length-g[u].x,g[fx].y=g[v].y-g[u].y;
else
g[fx].x=g[v].x-length-g[u].x,g[fx].y=g[v].y-g[u].y;
}
}
int main()
{
scanf("%d%d",&n,&m);
init();
for(int i=0;i<m;i++)
scanf("%d%d%d %c",&q[i].u,&q[i].v,&q[i].length,&q[i].s);
scanf("%d",&k);
for(int i=0;i<k;i++)
scanf("%d%d%d",&w[i].u,&w[i].v,&w[i].index),w[i].pos=i;
sort(w,w+k);
int ans,j=0;
for(int i=0;i<k;i++){
for(;j<w[i].index;j++)
join(q[j].u,q[j].v,q[j].length,q[j].s);
int u=w[i].u,v=w[i].v;
int fx=finds(u),fy=finds(v);
if(fx!=fy)
ans=-1;
else
ans=abs(g[u].x-g[v].x)+abs(g[u].y-g[v].y);
e[i].ans=ans,e[i].pos=w[i].pos;
}
sort(e,e+k,cmp);//恢复原来的1询问次序
for(int i=0;i<k;i++){
printf("%d\n",e[i].ans);
}
return 0;
}
.```