原题链接:https://www.luogu.org/problem/show?pid=1196
luogu 400AC纪念题
这道题也算是对于并查集的巧妙运用了。
首先解释一下数组的含义,f[i]表示i号战舰现在正在f[i]列中,num[i]表示目前第i列上有num[i]艘战舰,front[i]表示i号战舰是当前列的第front[i]艘战舰,
因为特殊的要求,所以在路径压缩的时候就要注意,不能只简单地寻找祖先,而要在寻找祖先的同时将自己所在列的所有战舰都合并到祖先的列,也就是将祖先的front值加到当前点的front值上。
在合并的指令时,因为当前战舰不一定是最后一艘,仅凭一个front已经不够用了,因此num派上了用场。
假设fx,fy分别表示x,y的祖先,将x所在列合并到y所在列的时候,就可以直接将num[fy]加到front[fx]上,同时更新num[fy],然后fx位置已经没有战舰了,于是可以清空为0。
每次询问的时候,首先判断x,y是否在同一列中,这个用并查集就能很快完成,在同一列的话,由于front就代表了他们的位置,所以abs(front[x]-front[y])-1。
#include<cstdio> int f[50005],front[50005],num[50005]; char s[5]; int abs(int x) { return x<0 ? -x : x; } int find(int x) { if(x==f[x]) return x; int fn=find(f[x]); front[x]+=front[f[x]]; return f[x]=fn; } int main() { int t,x,y; scanf("%d",&t); for(int i=0;i<=50000;i++) { f[i]=i; num[i]=1; } while(t--) { scanf("%s %d %d",s,&x,&y); int fx=find(x),fy=find(y); if(s[0]=='M') { front[fx]+=num[fy]; f[fx]=fy; num[fy]+=num[fx]; num[fx]=0; } else { if(fx!=fy) printf("-1 "); else printf("%d ",abs(front[x]-front[y])-1); } } return 0; }