您的位置:首页 > 其它

[树] cf 698B D Fix a Tree

2016-07-20 10:59 281 查看

题意

给定每个节点的父亲,判断是否为一棵有根树;若不是,改变最少的节点的父亲,使其成为有根树。(节点规模2*105)。

题目分析

比赛时一脸懵逼,后来看了大神代码——本题就是“见招拆招”:从叶子(尚未访问过的节点)往上找其最远的祖先,若能找到根,则合题;若找到环或找到与树不连通的祖先,则将祖先的父亲指向根。

代码中dep[i]代表i是第几批被访问的。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<algorithm>
using namespace std;
const int maxn=2e5+5;
int a[maxn];
int root=0;
int dep[maxn]={0};
int cnt=0;
int ans;
void work(int x)
{
dep[x]=++cnt;
while(dep[a[x]]==0)
x=a[x],dep[x]=cnt;
if(dep[a[x]]==cnt)//祖先是当前批次,则有可能是环、不连通
{
if(root==0) root=x;
if(a[x]!=root)//祖先是环或不连通
a[x]=root,ans++;
}
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
if(a[i]==i) root=i;
for(int i=1;i<=n;i++)
if(dep[i]==0) work(i);
cout<<ans<<endl;
for(int i=1;i<n;i++) printf("%d ",a[i]);cout<<a
<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  cf 算法 acm