题目大意:给出一个长度为n的数组a,要求输出两个排列p,q,使得对于所有i属于1到n,都有max(pi,qi)=ai
1<=n<=2e5;1<=ai<=n
思路:我们可以发现如果一个数字在a中出现了两次,那么p中一个位置需要这个数字,另一个位置就是要q中是这个数字,那么我们统计a中数字出现的次数,如果是第一次出现就让p中对应位置的数字等于它,第二次出现时就让q中对应位置的数字等于它,然后我们如果这个位置更新的p,就要记录对这个位置pi的值和数组下标,作为以后构造q数组的依据,同时分别记录哪些数字没有在排列p,q,中现过,然后我们将这些没有访问过的值放入大根堆中,并将之前记录的对组数组按数值排序,从大到小遍历,并依次将大根堆中的数放入即可,例如4,3,2,1在q中没有出现过,然后我们记录过p中5,4,3,2的位置,那么我们就从大到小依次让p中5,4,3,2的位置分别在q中放入4,3,2,1,最后再检验构造的两个数组是否满足排列的要求和最大值等于a的要求
//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int cnt[N];
int a[N], b[N];
pair<int,int> aa[N], bb[N];
int cnta[N], cntb[N];
int ma[N];
bool visa[N], visb[N];
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
bool flag = 1;
for (int i = 1; i <= n; i++)
{
a[i] = b[i] = 0;//p,q数组
cnt[i] = 0;//统计a中数字出现的次数
cnta[i] = cntb[i] = 0;//统计构造好的数组中数字出现的次数
visa[i] = visb[i] = 0;//统计哪些数字已经被添加进了p,q中
}
int tota = 0, totb = 0;
for (int i = 1; i <= n; i++)
{
cin >> ma[i];
cnt[ma[i]]++;
if (cnt[ma[i]] == 1)
{//第一次出现的,放入p中
a[i] = ma[i];
bb[++totb] = make_pair(ma[i], i);//记录数值,下标
visa[ma[i]] = 1;
}
else
{
b[i] = ma[i];
aa[++tota] = make_pair(ma[i], i);
visb[ma[i]] = 1;
}
}
priority_queue<int>qa, qb;//存放没被添加过的数
for (int i = 1; i <= n; i++)
{
if (!visa[i])
qa.push(i);
if (!visb[i])
qb.push(i);
}
sort(aa + 1, aa + 1 + tota);
sort(bb + 1, bb + 1 + totb);//按数值排序
for (int i = tota; i >= 1; i--)
{//从大到小遍历
a[aa[i].second] = qa.top();//依次取出堆顶数,放入对应下标的位置上
qa.pop();
}
for (int i = totb; i >= 1; i--)
{
b[bb[i].second] = qb.top();
qb.pop();
}
for (int i = 1; i <= n; i++)
{
cnta[a[i]]++;//统计构造好的数组中每个数出现的次数
cntb[b[i]]++;
}
for (int i = 1; i <= n; i++)
{
if (cnta[i] != 1 || cntb[i] != 1||max(a[i],b[i])!=ma[i])
{//每个数是否出现次数都是1,pi,qi最大值是都等于ai
flag = 0;
break;
}
}
if (!flag)
{
cout << "NO" << endl;
continue;
}
cout << "YES" << endl;
for (int i = 1; i <= n; i++)
{
cout << a[i]<<" ";
}
cout << endl;
for (int i = 1; i <= n; i++)
{
cout << b[i] << " ";
}
cout << endl;
}
return 0;
}