题意:一个数字对序列长度取模,如果取模后的序列没放数字则放这个位置,如果有位置,则往后放,现在给你一串已经放好的序列,问是否符合规则,如果符合,输出字典序最小的放入顺序。
思路:我们可以先把对n取余为那个位置的数放入优先队列,然后从优先队列出元素,并把它加+1的位置当做父亲,这样可以看出本来也应该在这个位置的数是不是往后找到第一个没放的位置,如果是压入队列,最后看你比较符合的个数和总的不为-1的个数,如果不同则不符合。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int p[N];
struct node
{
int x,y;
bool friend operator <(node a,node b)
{
return a.x>b.x;
}
};
int a[N];
int vis[N];
int b[N];
int findx(int x)
{
if(x==p[x])return x;
return p[x]=findx(p[x]);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
priority_queue<node>qu;
int n;
int cnt=0,num=0;
scanf("%d",&n);
node q;
for(int i=0;i<=n;i++)
p[i]=i;
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
q.x=a[i];
q.y=i;
if(a[i]==-1)continue;
cnt++;
if(a[i]%n==i)
{
qu.push(q);
vis[i]=1;
}
}
while(!qu.empty())
{
q=qu.top();
qu.pop();
b[num++]=q.x;
int v=p[findx(q.y)]=findx((q.y+1)%n);
if(vis[v]||a[v]==-1||findx(a[v]%n)!=v)continue;
q.x=a[v];
q.y=v;
qu.push(q);
vis[v]=1;
}
if(num<cnt)
{
printf("-1\n");
}
else
{
for(int i=0;i<num;i++)
{
if(i)printf(" ");
printf("%d",b[i]);
}
printf("\n");
}
}
return 0;
}