您的位置:首页 > 其它

[补题/研究] BUPT冬季训练Div.1 #1C: CodeForces - 699D Fix a Tree

2018-02-22 19:07 447 查看
Winter Training Div.1 #1 C题

D. Fix a Tree

A tree is an undirected connected graph without cycles.

一棵树是一个无向无环的连通图。

Let’s consider a rooted undirected tree with nn vertices, numbered 11 through nn. There are many ways to represent such a tree. One way is to create an array with nn integers p1, p2, ..., pnp1, p2, ..., pn, where pipi denotes a parent of vertex ii (here, for convenience a root is considered its own parent).

For this rooted tree the array pp is [2, 3, 3, 2][2, 3, 3, 2].



Given a sequence p1, p2, ..., pnp1, p2, ..., pn, one is able to restore a tree:

There must be exactly one index rr that pr = rpr = r. A vertex rr is a root of the tree.

For all other n − 1n − 1 vertices ii, there is an edge between vertex ii and vertex pipi.

A sequence p1, p2, ..., pnp1, p2, ..., pn is called valid if the described procedure generates some (any) rooted tree. For example, for n = 3n = 3 sequences (1,2,2),(2,3,1)(1,2,2),(2,3,1) and (2,1,3)(2,1,3) are not valid.

You are given a sequence a1, a2, ..., ana1, a2, ..., an, not necessarily valid. Your task is to change the minimum number of elements, in order to get a valid sequence. Print the minimum number of changes and an example of a valid sequence after that number of changes. If there are many valid sequences achievable in the minimum number of changes, print any of them.

Input

The first line of the input contains an integer n(2 ≤ n ≤ 200 000)n(2 ≤ n ≤ 200 000) — the number of vertices in the tree.

The second line contains nn integers a1, a2, ..., an(1 ≤ ai ≤ n)a1, a2, ..., an(1 ≤ ai ≤ n).

Output

In the first line print the minimum number of elements to change, in order to get a valid sequence.

In the second line, print any valid sequence possible to get from (a1, a2, ..., an)(a1, a2, ..., an) in the minimum number of changes. If there are many such sequences, any of them will be accepted.

Examples

Input

4
2 3 3 4


Output

1
2 3 4 4


Input

5
3 2 2 5 3


Output

0
3 2 2 5 3


Input

8
2 3 5 4 1 6 6 7


Output

2
2 3 7 8 1 6 6 7


Note

In the first sample, it’s enough to change one element. In the provided output, a sequence represents a tree rooted in a vertex 44 (because p4 = 4p4 = 4), which you can see on the left drawing below. One of other correct solutions would be a sequence 2 3 3 22 3 3 2, representing a tree rooted in vertex 33 (right drawing below). On both drawings, roots are painted red.



In the second sample, the given sequence is already valid.

题解

好的,我们来看一看给定数组下会破坏树的性质的地方有可能长什么样吧:

1.自环x=pre[x]x=pre[x]

2.类似这样

113→→714↓18→→6↑8↑15→←4→12←5↓2↑111→7→6→4→5↑↓13→148←12←2↓↑↑18→1511

不可能有长成其他样子的环。

那么我们可以利用父亲只有一个的特点,去发现这样破坏性质的环,然后将其修正。

1.自环很好判断:如果原始状态下,x=pre[x]x=pre[x],那么它必然是要纳入判断的。

2.其他环也很好判断:

对于并查集的合并,我们取一个例子会发现:

find(7)
1→7→6→4→5
↑ ↓
8←2
↑
10
->find(6)
1→7→4→4→5
↑ ↑ ↓
6 8←2
↑
10
->find(4)
1→7→5←5←5←6
↑   ↓
4←8←2
↑
10
->find(5)
5 10
↓ ↓
1→7→2←2←6
↑ ↓
4←8
->find(2)
->find(8)
->pre[all]=4


实际上最终也会压缩到环上一点,那么我们把这样的结点作为环的代表即可。

但是,这样并查集的find必须改成非递归形式。因为递归是先递后归,不找到原始即为自环的结点不罢休,但是非自环的环会使得递归陷入死循环。

这两种x=pre[x]x=pre[x]的区别就是后者实际上在find(x)的途中已经访问过。

时间复杂度:因为find在每个结点上只会判断一次,所以是O(n)O(n),可能的环最多有n个,每个也只判断一次,所以是O(n)O(n),所以时间复杂度最坏也是O(n)O(n).

测验:空间占用5400KB,时间耗费108ms,相当优秀.

$$

#include <cstdio>
#include <vector>
#define F(_i,_u) for(int _i=0;_i<(_u);_i++)
#define FF(_i,_l,_r) for(int _i=_l;_i<=(_r);_i++)
#define FS(_i,_r,_l) for(int _i=_r;_i>=(_l);_i--)
#define TRV(_i,_V) for(int _i=(_V).size()-1;_i+1;_i--)
#define PB push_back
#define all(x) x.begin(),x.end()
using namespace std;
//BigCycle:原始状态下成环的环上结点,Loop:原始状态下成自环的节点
vector<int> BigCycle,Loop;

//vis:是否访问过,added是否已经加入待修改数组中
bool vis[200005]={0},added[200005]={0};

//pre:prev该结点的父亲下标,a:题目所给数组
int pre[200005],a[200005];

inline int find(int x){
int t;
for(;;){
if(x==pre[x]){

//发现被压缩节点变成根节点
if(!added[x]){
if(!vis[x])Loop.PB(x);
else BigCycle.PB(x);
added[x]=1;
}

//这个vis不能放在前面,因为判断Loop和BigCycle要用到这个属性
vis[x]=1;
return x;
}

vis[x]=1;
//压缩
t=pre[x];
pre[x]=pre[t];
x=t;
}
}
int main(){
//cg:change,改变的父亲数目,Ances:ancestor,"钦定"的符合题意祖宗
int n,cg=0,Ances;

scanf("%d",&n);
FF(i,1,n){
scanf("%d",&a[i]);
pre[i]=a[i];
}

FF(i,1,n)if(!vis[i])find(i);

if(BigCycle.size())Ances=BigCycle[0];
if(Loop.size())Ances=Loop[0],cg--;
TRV(i,BigCycle)a[BigCycle[i]]=Ances,cg++;
TRV(i,Loop)a[Loop[i]]=Ances,cg++;

printf("%d\n",cg);
FF(i,1,n-1)printf("%d ",a[i]);printf("%d",a
);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: