题目描述
有一个划分为N列的星际战场,各列依次编号为1,2,…,N。
有N艘战舰,也依次编号为1,2,…,N,其中第i号战舰处于第i列。
有T条指令,每条指令格式为以下两种之一:
1、M i j,表示让第i号战舰所在列的全部战舰保持原有顺序,接在第j号战舰所在列的尾部。
2、C i j,表示询问第i号战舰与第j号战舰当前是否处于同一列中,如果在同一列中,它们之间间隔了多少艘战舰。
现在需要你编写一个程序,处理一系列的指令。
输入格式
第一行包含整数T,表示共有T条指令。
接下来T行,每行一个指令,指令有两种形式:M i j或C i j。
其中M和C为大写字母表示指令类型,i和j为整数,表示指令涉及的战舰编号。
输出格式
你的程序应当依次对输入的每一条指令进行分析和处理:
如果是M i j形式,则表示舰队排列发生了变化,你的程序要注意到这一点,但是不要输出任何信息;
如果是C i j形式,你的程序要输出一行,仅包含一个整数,表示在同一列上,第i号战舰与第j号战舰之间布置的战舰数目,如果第i号战舰与第j号战舰当前不在同一列上,则输出-1。
数据范围
$N≤30000,T≤500000$
样例
输入样例:
4
M 2 3
C 1 2
M 2 4
C 4 2
输出样例:
-1
1
并查集(边带权)
什么题目要用到并查集?那就是具有非常明显的传递关系的题目,或者说并查集擅长动态维护许多具有传递性的关系,能在无向图中维护节点之间的连通性.
这道题目要注意的就是,我们要边带权,也就是我们不能只处理集合的关系,而是要多一个附带的数组,这个数组就来记录这道题目中最特殊的间隔了多少战舰.听上去很高大上的边带权,实际上就是格外多了一个数组跟随着merge和find一起走而已.也就多了两三行代码,精简容易得很,直接上代码.
C++ 代码
#include <bits/stdc++.h>
using namespace std;
const int N=31000+10;
int fa[N],n,t,i,j,d[N],size[N];//size就是记录个数
int get(int x)
{
if (x==fa[x])
return x;
int root=get(fa[x]);
d[x]+=d[fa[x]];//往下推进
return fa[x]=root;
}
void merge(int x,int y)
{
x=get(x),y=get(y);
fa[x]=y,d[x]=size[y];
size[y]+=size[x];//顺带记录
}
int main()
{
scanf("%d\n",&t);
for(i=1;i<=30000;i++)
fa[i]=i,size[i]=1;
while(t--)
{
char ch=getchar();
scanf("%d %d\n",&i,&j);
if (ch=='M')
merge(i,j);
else
{
if (get(i)==get(j))
cout<<abs(d[i]-d[j])-1;
else
cout<<"-1";
cout<<endl;
}
}
return 0;
}
现在已经WA了哈,除size之外再修改两个地方即可:
1. 距离之差不能为负数,max(abs(d[i]-d[j])-1, 0)
2. 只有fa[x] != fa[y] 时才需要进行合并~
现在好像真的wa掉了
size改了名字也没用a
发现是当x == y的时候没有特判
合并的时候要判定一下不在同一集合
我在这个点上卡了很久…最后才发现是这个hack数据..
为什么scanf换成cin就输出都不对了?
读到了空格了吧
同问
并没有wa掉,只是管理员更新了c++版本,size是新版本的关键字,改成别的变量名字就好了 。
为什么现在这个题WA掉了呢
并没有wa掉,只是管理员更新了c++版本,size是新版本的关键字,改成别的变量名字就好了 。
这里为什么要把 root 单独记录下来呢,本人太菜了。。。
root记录的是祖先节点,不过您可以忽略掉,只不过我为了个人好理解,于是就多打了一个变量.
好的 谢谢
我应该是没有说清楚
程序1:
int tofind(int x)
{
if(x == fa[x]) return fa[x];
int root = tofind(fa[x]);
dis[x] += dis[fa[x]];
return fa[x] = root;
}
程序2:
int tofind(int x)
{
if(x == fa[x]) return fa[x];
dis[x] += dis[fa[x]];
int root = tofind(fa[x]);
return fa[x] = root;
}
程序1能过,但程序2就wa了,这里实在搞不懂是为什么
(感觉前后顺序都一样的啊。。)
实际上是再处理d[x]之前,递归处理d[f[x]]。
您说的好棒啊.
请问 get函数里 如果改为
int tofind(int x)
{
if(x == fa[x]) return fa[x];
dis[x] += dis[fa[x]];
return fa[x] = tofind(fa[x]);
}
这样就是错的,请问为什么呢
建议您画个图,模拟一遍并查集合并的情况.