POJ-1984-Navigation Nightmare+带权并查集(中级
参考:1:https://www.cnblogs.com/huangfeihome/archive/2012/09/07/2675123.html
参考:2:http://blog.csdn.net/tc_to_top/article/details/43447727
题意:先给出一个四方形的城市地图的全部信息,
然后在只知道前k条信息的情况下,询问a,b之间的距离,若没连通,输出-1;
思路:
首先,每次询问的K是按升序排列的(讨论版里神牛说的,还有就是题号很有深意);
这道题让我对并查集有一个新的认识:根的代表性是非常强的!并查集里如果某个节点的改动会影响到整个并查集的所有节点,那么,在union_set的时候只需要改动根节点就可以了,当然,在find_set函数里要对所有节点进行更新(这相当于一种延时标记)。我们知道,find_set函数走了两条路,一条是前往根的路,一条是从跟返回的路,那么,如果发现根已经被改动,必须在从根返回的路上更新经过的所有节点。这在find_set函数里是可以实现的。
//样例 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
模拟一遍样例,这里是执行完Find(1-7)以后的坐标
t = 1: x[1] = 0, y[1] = 0
x[6] = 13, y[6] = 0
t = 2: x[1] = 0, y[1] = 0
x[6] = 13, y[6] = 0
x[3] = 22, y[3] = 0
t = 3: x[1] = 0, y[1] = 0
x[6] = 13, y[6] = 0
x[3] = 22, y[3] = 0
x[5] = 22, y[5] = -7
t = 4(换原点):
x[4] = 0, y[4] = 0
x[1] = 0, y[1] = 3
x[6] = 13, y[6] = 3
x[3] = 22, y[3] = 3
x[5] = 22, y[5] = -4
t = 5(换原点):
x[2] = 0, y[2] = 0
x[4] = -20,y[4] = 0
x[1] = -20,y[1] = 3
x[6] = -7, y[6] = 3
x[3] = 2, y[3] = 3
x[5] = 2, y[5] = -4
t = 6: x[2] = 0, y[2] = 0
x[4] = -20,y[4] = 0
x[1] = -20,y[1] = 3
x[6] = -7, y[6] = 3
x[3] = 2, y[3] = 3
x[5] = 2, y[5] = -4
x[7] = -20,y[7] = -2
/* 带权并查集; */ #include <cstdio> #include <algorithm> #include <iostream> #include <cstring> using namespace std; const int maxn = 40009; int n,m,fa[maxn],s[maxn],h[maxn]; struct node{ int a,b,len; char c[5]; }mp[maxn]; void init(){ for(int i=1;i<=n;i++) fa[i]=i; memset(s,0,sizeof(s)); memset(h,0,sizeof(h)); } int ab(int x,int y) { if(x-y>0)return x-y; else return y-x; } int find(int x) { if(fa[x]==x)return x; int tmp = fa[x]; fa[x]=find(fa[x]); h[x] = h[x] + h[tmp]; // 从根回来的路上更新子节点 s[x] = s[x] + s[tmp]; return fa[x]; } void uni(node t,int dx,int dy) { int px = find(t.a); int py = find(t.b); if(px==py)return; fa[px]=py; // 随意合并 h[px] = h[t.b] - h[t.a] + dx;// 暂且只对根进行偏移 s[px] = s[t.b] - s[t.a] + dy; } int main(){ scanf("%d%d",&n,&m); init(); for(int i=0;i<m;i++) { scanf("%d%d%d%s",&mp[i].a, &mp[i].b, &mp[i].len, mp[i].c); } int q,k=0; scanf("%d",&q); while(q--) { int l,r,e; scanf("%d%d%d",&l,&r,&e); for(int i=k;i<e;i++) { int dx=0,dy=0; switch(mp[i].c[0]) { case 'N':dy+=mp[i].len;break; case 'S':dy-=mp[i].len;break; case 'E':dx+=mp[i].len;break; case 'W':dx-=mp[i].len;break; } uni(mp[i],dx,dy); } k=e; int pl=find(l),pr=find(r); if(pl!=pr) { puts("-1"); } else { printf("%d\n",ab(h[l],h[r])+ab(s[l],s[r])); } } return 0; }