题目大意:有30000个船,第i个船在第i列,两个操作,M:把第i列的船整体拼到第j列船后,C:求第i和第j个船之间的船的个数
题解:可以想到用并查集,在基础的并查集上增加路径,用num数组存第i个船到队首的距离,用len存这一列的船的个数。问题主要在路径压缩上维护num数组上。可以在find的过程中,每改变f[x]的时候把num[i]加上num[f[i]],就可以维护了。
卡点:在num数组初始赋值为了1,导致每find一遍,所搜索的值就加了1(根节点)。没看清要求求的是中间船的个数,写成了包括两头的。在求出答案时,误把num[i]-num[j]写成了num[find[i]]-num[find[j]]
C++ Code:
#include<cstdio> #include<cstdio> const int maxn=30010; int n,f[maxn],num[maxn],len[maxn]; char ch[5]; int find(int x){ if (x==f[x])return x; int xx=find(f[x]); num[x]+=num[f[x]]; return f[x]=xx; } int abs(int a){return a>0?a:-a;} int main(){ scanf("%d\n",&n); for (int i=1;i<maxn;i++)f[i]=i,len[i]=1; while (n--){ int a,b; scanf("%s%d%d",ch,&a,&b); if (ch[0]==‘M‘){ int x=find(a),y=find(b); if (x==y)continue; num[x]=len[y]; len[y]+=len[x]; f[x]=y; }else{ int x=find(a),y=find(b); if (x!=y){ puts("-1"); continue; } printf("%d\n",abs(num[a]-num[b])-1); } } return 0; }