一.战舰
1.题目
题目描述:
有1~n艘战舰,编号分别是1~n。开始,第i号战舰在第i列上。有m条命令,命令一共包含2种1、M, ij,将i号战舰所在的列的全部战舰,保持原有顺序接到第i列战舰后面;2、Cij,查询第i号战舰和第j号战舰是否在同一列,如果是中间间隔多少搜战舰。 (如果不在同一列,输出-1)n<=30000,m<500000)
样例输入:
4 4
M 2 3
C 1 2
M 2 4
C 4 2
样例输出:
-1
1
2.思路:
看到题,我们不难发现,这个可以建模为并查集,因为有明显特征嘛,不多赘述。
步骤一:
实现初始值和M的简单功能(不考虑路径距离)
#include<bits/stdc++.h>
uisng namespace std;
// 并查集数组 到祖先的距离 有多少成员
int fa[30010] , dis[30010] , size[30010];
int find(int x){
if(fa[x]==x) return x;
int t=find(fa[x]);
return fa[x]=t; //路径压缩
}
void merge(int x,int y){
int fx=find(x);
int fy=find(y);
fa[fy]=fx;
}
int main(){
int n;
cin>>n;
//初始值
for(int i=1;i<=n;i++){
fa[i]=i;
size[i]=1;
}
int m;
cin>>m;
char s;
int x,y;
for(int i=1;i<=m;i++){
cin>>s>>x>>y;
int fx=find(x);
int fy=find(y);
if(s=='M'){
merge(x,y);
}
}
return 0;
}
步骤二:
实现简单的距离计算,即初始进行M操作时的步骤
举个栗子:
如题:我们把3 合并到 2,当然,距离也要改变,经推算,不难发现,3距离父节点的长度即为2的size。(如果单看,可能数据对不上,因为输出结果时,ans还要-1)
代码主要变化为:
步骤三:
实现C的功能,查询是否在同一列比较简单,直接判断fx==fy,但找距离,我们要注意find函数,经过步骤二,我们只实现了初始的marge,这是没有祖先节点的,这里我们要处理有祖先节点的。
所以结果也为:a到b的距离为|(a到祖先节点的距离-b到祖先节点的距离-1)|
即dis[a][b]=abs(dis[a]-dis[b]-1)
代码主要变化:
find()函数
实现C的功能
3.AC代码(带详细注释)
#include<bits/stdc++.h>
using namespace std;
// 父节点 到根节点的距离 战舰数量
int fa[30010],dis[30010],size[30010];
int find(int x){
if(fa[x]==x) return x; //如果当前节点的父节点就是自己,说明已经找到了祖先节点,直接返回
int pre=fa[x]; //记录当前节点的父节点
int t=find(fa[x]); //递归查找祖先节点
dis[x]+=dis[pre]; //当前节点到祖先节点的距离要加上父节点到祖先节点的距离
return fa[x]=t; //路径压缩,将当前节点的父节点设为祖先节点
}
void merge(int x,int y){
int fx=find(x); //查找x所在的集合的祖先节点
int fy=find(y); //查找y所在的集合的祖先节点
fa[fx]=fy; //将x所在的集合的祖先节点的父节点设为y所在的集合的祖先节点
dis[fx]=size[fy]; //当前节点到父节点的距离=父节点的长度
size[fy]+=size[fx]; //更新y所在集合的大小
}
int main(){
int n,m;
cin>>n>>m;
//初始化
for(int i=1;i<=n;i++){
fa[i]=i; //每个节点的父节点初始化为自己
size[i]=1; //每个节点所在集合的大小初始化为1
}
char s;
int x,y;
for(int i=1;i<=m;i++){
cin>>s>>x>>y;
int fx=find(x); //查找x所在的集合的祖先节点
int fy=find(y); //查找y所在的集合的祖先节点
if(s=='M'){ //合并操作
merge(fx,fy); //将x所在的集合合并到y所在的集合中
}else{ //查询操作
if(fx!=fy) cout<<-1<<endl; //如果x和y不在同一个集合中,输出-1
else{
//输出x和y到其公共祖先节点的距离之差的绝对值减1
cout<<abs(dis[x]-dis[y])-1<<endl;
}
}
}
return 0;
}