返回题解分享
讨论 / 题解分享/ 帖子详情

传送阵(编程题) - 题解

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int a[N],p[N],cnt[N],sum,n;

int find(int x){
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}

signed main()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        p[i]=i;
        cnt[i]=1; 
    }
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        int a=find(i),b=find(x);
        if(a==b) continue;
        p[b]=a;
        cnt[a]+=cnt[b];
    }
    for(int i=1;i<=n;i++){
        int a=find(i),b=find(i+1);
        if(a==b) sum=max(sum,cnt[a]);
        else{
            sum=max(sum,cnt[a]+cnt[b]);
        }
    }
    cout<<sum<<endl;
    return 0;
}
3 回复 0 转发 0 喜欢 18 阅读
回复 (3)
默认 最新
露米 2026/4/18
谢谢你分享的题解,并查集的实现非常扎实。用 cnt 数组直接维护集合大小,让最后的统计逻辑变得很直观。

在代码最后尝试合并相邻区域的逻辑很有意思。不过我注意到,当 i 运行到 n 的时候,find(i+1) 可能会访问到预设范围之外。不知道这道题的边界是不是有特殊的定义,比如 $n$ 和 $1$ 是首尾相接的呢?

如果能稍微补充一下这部分的解题背景,相信对正在思考这道题的小伙伴会很有帮助。这种不断优化边界细节的过程,也是编程的乐趣所在,加油 🙂
对了,还有一个小细节:在 main 函数里,局部变量 a 和全局数组 a[N] 同名了。虽然在目前的逻辑下不会报错,但如果以后代码逻辑变得更复杂,可能会给调试带来一点点困扰,给它们起个不一样的名字或许会更稳妥。

另外,看到你细心地使用了 long long,这种预防数据溢出的习惯非常稳健。如果后续题目涉及的数据量非常大,也可以尝试加上 ios::sync_with_stdio(0),让输入输出
0
露米 2026/3/15
并查集的思路用得很扎实,代码整体看起来非常清晰。

关于最后统计最大连通块的逻辑,我猜你是不是在考虑通过连接相邻的两个区域,来尝试获取更大的连通效果?这种通过 cnt[a] + cnt[b] 来计算合并潜力的做法很直观。

如果能稍微补充一下题目的具体背景(比如是否限定了只能连接相邻的传送阵),相信对正在思考这道题的小伙伴们会更有启发。

这种一点点完善思路的过程最有成就感了,
期待看到你更多的思考和分享,加油 🙂
0
露米 2026/2/23
谢谢分享你的题解。

用并查集来处理传送阵的连通性是一个很直观的思路,代码的结构也很清晰,尤其是通过 cnt 数组维护集合大小的做法,让最后的统计变得很方便。

我注意到在最后一个循环中,代码会检查 ii+1 的所属集合。当 i 达到 n 的时候,find(i+1) 可能会访问到初始范围之外的索引。不知道这道题的边界条件里,是不是 $n$ 和 $1$ 也是相邻的,或者有特殊的范围规定呢?

如果能稍微补充一下这部分的解题思路,相信对正在思考这道题的小伙伴会更有启发 🙂
另外,看到你细心地使用了 long long,这种考虑到数据溢出的习惯非常稳健。

期待你的后续分享,加油。
0