给定一个 1 ∼ n 1∼n 1∼n 的排列 f 1 , f 2 , … , f n f_1,f_2,…,f_n f1,f2,…,fn。
已知,对于 1 ≤ i ≤ n 1≤i≤n 1≤i≤n, f i ≠ i f_i≠i fi=i 始终成立。
现在,因为一些原因,数组中的部分元素丢失了。
请你将数组丢失的部分补全,要求数组在补全后仍然是一个 1 ∼ n 1∼n 1∼n 的排列,并且对于 1 ≤ i ≤ n 1≤i≤n 1≤i≤n, f i ≠ i f_i≠i fi=i 均成立。
输入格式
第一行包含整数
T
T
T,表示共有
T
T
T 组测试数据。
每组数据第一行包含一个整数 n n n。
第二行包含 n n n 个整数 f 1 , f 2 , … , f n f_1,f_2,…,f_n f1,f2,…,fn。如果 f i = 0 f_i=0 fi=0,则表示 f i f_i fi 已经丢失,需要补全。
输出格式
每组数据一行,输出补全后的
f
f
f 数组,整数之间空格隔开。
如果方案不唯一,则输出任意合理方案即可。
数据范围
1
≤
T
≤
100
,
1≤T≤100,
1≤T≤100,
2
≤
n
≤
2
×
1
0
5
,
2≤n≤2×10^5,
2≤n≤2×105,
0
≤
f
i
≤
n
,
0≤f_i≤n,
0≤fi≤n,至少两个
f
i
f_i
fi 为
0
0
0。
同一测试点内所有
n
n
n 的和不超过
2
×
1
0
5
2×10^5
2×105。
数据保证有解。
输入样例:
3
5
5 0 0 2 4
7
7 0 0 1 4 0 6
7
7 4 0 3 0 5 1
输出样例:
5 3 1 2 4
7 3 2 1 4 5 6
7 4 2 3 6 5 1
#include
#include
#include
using namespace std;
const int N = 200010;
int n;
int pre[N], ne[N];
bool st[N]; // 标记孤立点
int main(){
int t;
scanf("%d", &t);
while(t--){
scanf("%d", &n);
memset(ne, 0, 4*(n+1));
memset(pre, 0, 4*(n+1));
memset(st, 0, n+1); // 孤立点
for(int i = 1; i <= n; i++) scanf("%d", &ne[i]), pre[ne[i]] = i;
vector<int> v;
for(int i = 1; i <= n; i++)
if(!ne[i] && !pre[i]){
v.push_back(i);
st[i] = true;
}
bool flag = false;
for(int i = 1; i <= n; i++){
if(!st[i] && ne[i] && !pre[i]){ // 开环的头节点
int u = ne[i]; // 尾
while(ne[u]) u = ne[u];
if(!flag){
for(int j = 0; j < v.size(); j++){
ne[u] = v[j];
u = ne[u];
}
flag = true;
}
ne[u] = i; // 连成环
}
}
int hh = 0, tt = 0;
if(!flag){ // 如过孤立点没有被插入任何一个开环,则他们自己成环
for(int i = 0; i < v.size(); i++)
if(!hh && !tt) hh = tt = v[i];
else ne[tt] = v[i], tt = v[i];
ne[tt] = hh;
}
for(int i = 1; i <= n; i++) printf("%d ", ne[i]);
puts("");
}
return 0;
}