专栏文章

题解:AT_abc401_e [ABC401E] Reachable Set

AT_abc401_e题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipmtuna
此快照首次捕获于
2025/12/03 14:34
3 个月前
此快照最后确认于
2025/12/03 14:34
3 个月前
查看原文

思路

看到好多大佬都用了并查集来做,小蒟蒻膜拜,只能给出一个奇奇怪怪的做法。
考虑递增枚举 kk 正向加点,可以发现如果这张图满足要求,第 kk 个点的来源必定小于 kk。所以可以在每次加点的时候把与它相连接的点记下来。
如果第 kk 个点没有被记下来,则说明无法完成,输出 1-1
否则,还需要查看是否一到 kk 全能被到达。可以发现之前没被收录的那些点只能通过点 kk 进行拓展。所以,从 kk 跑 dfs。注意,大于 kk 的点不跑。最后查看是否所有点都被收录了。
答案就是被收录点集的大小减去 kk

AC Code:

CPP
#include<bits/stdc++.h>
using namespace std;
long long n,m,mp[200005],ans;
vector<long long>poi[200005];
inline void dfs(long long now,long long lm){
    for(int i=0;i<poi[now].size();i++){
        if(mp[poi[now][i]]==0){
            ans++;
            mp[poi[now][i]]=1;
            if(poi[now][i]<=lm)dfs(poi[now][i],lm);
        }
    }
}
int main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=m;i++){
        long long a,b;
        scanf("%lld%lld",&a,&b);
        poi[a].push_back(b);
        poi[b].push_back(a);
    }
    mp[1]=1;
    ans=1;
    for(int i=0;i<poi[1].size();i++){
        mp[poi[1][i]]=1;
        ans++;
    }
    printf("%lld\n",ans-1);
    long long last=1;//优化,只用从上一个成功的 k 往下 check 即可。
    for(int i=2;i<=n;i++){
        if(mp[i]==1){
            dfs(i,i);
            long long flag=1;
            for(int j=last;j<=i;j++){//优化
                if(mp[j]==0){
                    flag=0;
                    break;
                }
            }
            if(flag==1)printf("%lld\n",ans-i),last=i;
            else printf("-1\n");
        }
        else{
            printf("-1\n");
        }
    }
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...