感觉自己很恍惚,真的是越来越菜了。
题目:给一个哈希表,判断哈希表是不是合法,合法的话求一个字典序最小的插入序列,不合法输出-1
思路:建图好困难,比赛时自己建图乱七八糟,赛后看了大佬的代码才最终完成自己的。题解是线段树建图...emm没用过。
记录一个movl[i]表示这个点可以往前移动的合法步数,过程中找前面的可行点连边,movl路径压缩。总共连边数最多最多也是不会超过2n的,O(n)建图。
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
struct node1
{
int v,next;
};
node1 edge[2*maxn];
struct node2
{
bool friend operator < (node2 n1,node2 n2){
return n1.val>n2.val;
}
int id,val;
};
priority_queue<node2> que;
int ary[maxn],first[maxn],degree[maxn];
int ans[maxn];
int tot;
void addedge(int u,int v)
{
edge[tot].v=v;
edge[tot].next=first[u];
first[u]=tot++;
}
int n,nu;
void toposort()
{
node2 cur,tmp;
while(!que.empty()) que.pop();
int num=0,i,u,v;
for(i=0;i<n;i++)
if(degree[i]==0&&ary[i]!=-1)
{
tmp.id=i,tmp.val=ary[i];
que.push(tmp);
}
while(!que.empty())
{
cur=que.top();
que.pop();
ans[num++]=cur.val;
u=cur.id;
for(i=first[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
degree[v]--;
if(degree[v]==0&&ary[v]!=-1)
{
tmp.id=v,tmp.val=ary[v];
que.push(tmp);
}
}
}
if(num!=nu) puts("-1");//散列表不合法
else//num==0时只输出一个换行
{
for(i=0;i<num;i++)
{
printf("%d",ans[i]);
if(i<num-1) printf(" ");
}
puts("");
}
}
int t;
int movl[maxn];
int main()
{
scanf("%d",&t);
while(t--)
{
nu=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&ary[i]);
if(ary[i]!=-1) nu++;
movl[i]=1;
}
tot=0;
memset(first,-1,sizeof first);
memset(degree,0,sizeof degree);
int flag=1;
for(int i=0;i<n;i++)
{
if(ary[i]==-1) continue;
if(ary[i]%n==i) continue;//这个点就在自己该在的位置
int k=ary[i]%n;//本该在k这个位置的
int j=(i-1+n)%n;//前一个位置
while(1)
{
if(ary[j]==-1)//在没到达该放位置前遇到了-1,说明散列表是不合法的
{
flag=0;
break;
}
addedge(j,i);
degree[i]++;
movl[i]+=movl[j];//相当于压缩路径了
int dis=(i-k+n)%n;//距离本来该放位置的距离
if(dis>=movl[i])
j=(j-movl[j]+n)%n;//j往前移
else break;
}
if(!flag) break;
}
if(flag)
toposort();//拓扑排序
else puts("-1");
}
return 0;
}
/*
100
9
16 -1 -1 -1 -1 -1 -1 7 8
4
8 5 2 3
10
8 10 -1 -1 34 75 86 55 88 18
2
1 2
5
100000 1000000000 111 1154 1123
*/