B. Fix a Tree(思维+判环构造+细节)

https://codeforces.com/problemset/problem/698/B


题意:

修复一棵树,给出一棵树的父节点,然后他可能存在环而变成了图,或者根节点不为1.
 

思路:

考虑环的影响,需要dfs判环。然后把环上的端点存下来。如果没有环就随便放一个。然后把不同连通块的连起来。

很细节的一个地方

有单个点的联通的时候要把边连到单点上

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2e5+1000;
typedef long long LL;
inline LL read(){LL x=0,f=1;char ch=getchar();	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
LL fa[maxn];
LL dfn[maxn],tot=0;
vector<LL>p;
vector<LL>g[maxn];
bool flag=1;
///无环保持,有环将环上的端点拆了
void dfs(LL u,LL last){
     dfn[u]=++tot;
     for(LL i=0;i<g[u].size();i++){
        LL v=g[u][i];
        if(v==last) continue;
        if(dfn[v]&&flag==1){
            flag=0;
            p.push_back(v);
        }
        else if(!dfn[v]){
            dfs(v,u);
        }
     }
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n;cin>>n;
  for(LL i=1;i<=n;i++){
      LL u=i;LL v;cin>>v;
      fa[u]=v;
      g[u].push_back(v);
      g[v].push_back(u);
  }
  for(LL i=1;i<=n;i++){
     if(!dfn[i]){
        flag=1;tot=0;
        dfs(i,-1);
        if(flag==1) p.push_back(i);
     }
  }
  LL ans=0;
  ///LL anc=(*p.rbegin());
  LL anc=0;
  for(LL i=0;i<p.size();i++){
    if(fa[p[i]]==p[i]){
        anc=p[i];
        break;
    }
    else anc=p[i];
  }
  for(LL i=0;i<p.size();i++){
    if(fa[p[i]]!=anc) ans++;
    fa[p[i]]=anc;
  }
  cout<<ans<<"\n";
  for(LL i=1;i<=n;i++){
    cout<<fa[i]<<" ";
  }
  cout<<"\n";
return 0;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/115215502