所謂帶權並查集
本題所求的不止是兩個編號之間是否有關係,還要求兩個編號之間有什麼關係,這就要求我們維護多個數組,fa[]數組維護兩個編號之間的連通性,dis[]維護編號爲i的戰艦到fa[i]之間的距離,num[]維護編號爲i的戰艦所在的那一列有多少戰艦。
find函數
int find(int x){
if(x!=fa[x]){
int k=fa[x];
fa[x]=find(fa[x]);
dis[x]+=dis[k];
num[x]=num[fa[x]];
}
return fa[x];
}
每次find的時候都更新num數組與dis數組
合併函數
void merge(int x,int y){
int r1=find(x),r2=find(y);
if(r1!=r2){
fa[r1]=r2;
dis[r1]=dis[r2]+num[r2];
num[r2]+=num[r1];
num[r1]=num[r2];
}
}
合併時由於是將i號戰艦所在的那一列併到j號所在列的尾端,所以dis[r1]=dis[r2]+num[r2]。
詢問函數
int query(int a,int b){
int r1=find(a),r2=find(b);
if(r1!=r2){
return -1;
}else {
return abs(dis[a]-dis[b])-1;
}
}
注意返回時要加一
AC代碼:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=30005;
int read(){
int rv=0,fh=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') fh=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
rv=(rv<<1)+(rv<<3)+c-'0';
c=getchar();
}
return rv*fh;
}
int fa[MAXN],dis[MAXN],t,num[MAXN];
int find(int x){
if(x!=fa[x]){
int k=fa[x];
fa[x]=find(fa[x]);
dis[x]+=dis[k];
num[x]=num[fa[x]];
}
return fa[x];
}
void merge(int x,int y){
int r1=find(x),r2=find(y);
if(r1!=r2){
fa[r1]=r2;dis[r1]=dis[r2]+num[r2];
num[r2]+=num[r1];
num[r1]=num[r2];
}
}
int query(int a,int b){
int r1=find(a),r2=find(b);
if(r1!=r2){
return -1;
}else {
return abs(dis[a]-dis[b])-1;
}
}
int main(){
freopen("in.txt","r",stdin);
t=read();
for(int i=1;i<=MAXN;i++) {fa[i]=i;num[i]=1;}
for(int i=1;i<=t;i++){
char c;
scanf(" %c ",&c);
int a=read(),b=read();
if(c=='M'){
merge(a,b);
}else {
printf("%d\n",query(a,b));
}
}
fclose(stdin);
return 0;
}