题意:有多个点,在平面上位于坐标点上,给出一些关系,表示某个点在某个点的正东/西/南/北方向多少距离,然后给出一系列询问,表示在第几个关系给出后询问某两点的曼哈顿距离,或者未知则输出-1。
只要在元素的权值上保存两个信息,与祖先元素的两个方向的差,我选择正东和正北方向差(负值表示正西和正南),然后直接用带权并查集,询问时曼哈顿距离就是两个权值的绝对值之和。由于询问是嵌在给出关系中间的,所以要先存下所有关系和询问,离线做就行。
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxm=4e4+10; 6 7 int fa[maxm],north[maxm],east[maxm]; 8 int a[maxm],b[maxm],l[maxm],ans[10005]; 9 char s[maxm][3]; 10 struct que{ 11 int num,a,b,t; 12 bool operator < (const que a)const{ 13 return t<a.t; 14 } 15 }q[10005]; 16 17 int abs(int a){return a>0?a:-a;} 18 19 void init(int n){ 20 for(int i=1;i<=n;++i){ 21 fa[i]=i; 22 north[i]=east[i]=0; 23 } 24 } 25 26 int find(int x){ 27 int r=x,t1,t2,t3,cn=0,ce=0; 28 while(r!=fa[r]){ 29 cn+=north[r]; 30 ce+=east[r]; 31 r=fa[r]; 32 } 33 while(x!=r){ 34 t1=fa[x]; 35 t2=cn-north[x]; 36 t3=ce-east[x]; 37 north[x]=cn; 38 east[x]=ce; 39 fa[x]=r; 40 cn=t2; 41 ce=t3; 42 x=t1; 43 } 44 return r; 45 } 46 47 int main(){ 48 int n,m; 49 scanf("%d%d",&n,&m); 50 init(n); 51 for(int i=1;i<=m;++i)scanf("%d%d%d%s",&a[i],&b[i],&l[i],s[i]); 52 int k; 53 scanf("%d",&k); 54 for(int i=1;i<=k;++i){ 55 scanf("%d%d%d",&q[i].a,&q[i].b,&q[i].t); 56 q[i].num=i; 57 } 58 sort(q+1,q+k+1); 59 int pos=1; 60 for(int i=1;i<=m;++i){ 61 int x=find(a[i]),y=find(b[i]); 62 int Cn=0,Ce=0; 63 if(s[i][0]==‘N‘)Cn=l[i]; 64 else if(s[i][0]==‘S‘)Cn=-l[i]; 65 else if(s[i][0]==‘E‘)Ce=l[i]; 66 else if(s[i][0]==‘W‘)Ce=-l[i]; 67 if(x!=y){ 68 fa[x]=y; 69 north[x]=north[b[i]]+Cn-north[a[i]]; 70 east[x]=east[b[i]]+Ce-east[a[i]]; 71 } 72 73 while(q[pos].t==i&&pos<=k){ 74 x=find(q[pos].a); 75 y=find(q[pos].b); 76 if(x!=y)ans[q[pos].num]=-1; 77 else ans[q[pos].num]=abs(north[q[pos].a]-north[q[pos].b])+abs(east[q[pos].a]-east[q[pos].b]); 78 pos++; 79 } 80 } 81 for(int i=1;i<=k;++i)printf("%d\n",ans[i]); 82 return 0; 83 }
时间: 2024-10-11 17:23:30