BZOJ 3362 POJ 1984 Navigation Nightmare 带权并查集
题目大意:一些农场由一些东西向或者南北向的路相互连接。在不断加边的过程中会询问两个农场的曼哈顿距离是多少,如果目前还不连通,那么输出-1。
思路:带权并查集,f[i]为点i到father[i]的距离,要维护两个值,一个是东西向的距离,一个是南北向的距离,因为以后更新的时候要用到。在合并的时候有些特殊。现在有一条边(x->y),设fx为x的根,fy为y的根,那么现在知道f到fx的距离,y到fy的距离,还知道x到y的距离,设fx到fy的距离为dis,则dis + f[y] = f[x] + edge[p].w,那么dis = f[x] - f[y] + edge[p].w。根据这个公式来合并两个树就可以了。
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 40010 using namespace std; struct Complex{ int x,y,len; char c; }edge[MAX]; struct Ask{ int x,y; int pos,_id; bool operator <(const Ask &a)const { return pos < a.pos; } }ask[MAX]; struct Status{ int x,y; Status(int _,int __):x(_),y(__) {} Status() {} Status operator +(const Status &a)const { return Status(x + a.x,y + a.y); } Status operator -(const Status &a)const { return Status(x - a.x,y - a.y); } }f[MAX]; int points,edges,asks; int father[MAX]; int ans[MAX]; char s[10]; void Pretreatment(); int Find(int x); int main() { cin >> points >> edges; Pretreatment(); for(int i = 1;i <= edges; ++i) { scanf("%d%d%d%s",&edge[i].x,&edge[i].y,&edge[i].len,s); edge[i].c = s[0]; } cin >> asks; for(int i = 1;i <= asks; ++i) scanf("%d%d%d",&ask[i].x,&ask[i].y,&ask[i].pos),ask[i]._id = i; sort(ask + 1,ask + asks + 1); int now = 1; for(int i = 1;i <= edges; ++i) { int fx = Find(edge[i].x); int fy = Find(edge[i].y); if(fx != fy) { father[fy] = fx; Status temp; if(edge[i].c == 'N') temp = Status(0,edge[i].len); if(edge[i].c == 'S') temp = Status(0,-edge[i].len); if(edge[i].c == 'E') temp = Status(edge[i].len,0); if(edge[i].c == 'W') temp = Status(-edge[i].len,0); f[fy] = f[edge[i].x] - f[edge[i].y] + temp; } while(i >= ask[now].pos && now <= asks) { int fx = Find(ask[now].x); int fy = Find(ask[now].y); if(fx != fy) ans[ask[now]._id] = -1; else { Status temp = f[ask[now].x] - f[ask[now].y]; ans[ask[now]._id] = abs(temp.x) + abs(temp.y); } ++now; } } for(int i = 1;i <= asks; ++i) printf("%d\n",ans[i]); return 0; } void Pretreatment() { for(int i = 1;i <= points; ++i) father[i] = i; } int Find(int x) { if(father[x] == x) return x; int temp = father[x]; father[x] = Find(father[x]); f[x] = f[x] + f[temp]; return father[x]; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。