https://www.nowcoder.com/acm/contest/142/J
这题竟然卡memset.. 一开始t了以为数组开小了 就往大了搞..
首先是判矛盾 如果i位置上的一个数ary[i] 本来应该在ary[i]%n=j处 那j到i之间肯定不能有负数 前缀和判断一下
如果暂时没矛盾 那就将从j到i-1的位置都向i连一条边 因为ary[i]这个数会出现在i这个位置就是因为j到i-1都被别的数占了 这个过程用线段树优化 然后拓扑排序判环 同时把队列带上优先级 因为题目要求字典序最小
至于线段树建图后的度数关系 一开始想的是提前记录下线段树每个节点对应的区间长度 但其实和区间长度没有一点关系 因为子区间度数不为零 那父区间也不可能被遍历
还有就是如果队列中有非线段树叶节点(即代表区间长度大于1的节点)的话 要先把这些节点弹出然后松弛其他点 因为可能会有更小的符合拓扑关系的数被这些非叶节点盖住
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
struct node1
{
int v;
int next;
};
struct node2
{
bool friend operator < (node2 n1,node2 n2)
{
return n1.val>n2.val;
}
int id;
int val;
};
node1 edge[6400010];
int ary[200010],pre[200010],ans[200010],mp1[200010],mp2[1600010],first[1600010],degree[1600010];
int n,num,tot,cnt;
inline void addedge(int u,int v)
{
edge[num].v=v;
edge[num].next=first[u];
first[u]=num++;
degree[v]++;
}
void build(int l,int r,int cur)
{
int m;
mp2[cur]=-2;
if(l==r)
{
mp1[l]=cur,mp2[cur]=l;
tot=max(tot,cur);
return;
}
addedge(2*cur,cur);
addedge(2*cur+1,cur);
m=(l+r)/2;
build(l,m,2*cur);
build(m+1,r,2*cur+1);
}
inline void update(int pl,int pr,int tar,int l,int r,int cur)
{
int m;
if(pl<=l&&r<=pr)
{
addedge(cur,mp1[tar]);
return;
}
m=(l+r)/2;
if(pl<=m) update(pl,pr,tar,l,m,2*cur);
if(pr>m) update(pl,pr,tar,m+1,r,2*cur+1);
}
void toposort()
{
priority_queue <node2> que;
node2 cur,tmp;
int i,u,v;
num=0;
for(i=0;i<n;i++)
{
if(ary[i]!=-1) num++;
}
for(i=1;i<=tot;i++)
{
if(mp2[i]!=-1&°ree[i]==0)
{
tmp.id=i,tmp.val=ary[mp2[i]];
que.push(tmp);
}
}
cnt=0;
while(!que.empty())
{
cur=que.top();
que.pop();
u=cur.id;
if(mp2[u]!=-2&&cur.val!=-1) ans[cnt++]=cur.val;
for(i=first[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
degree[v]--;
if(degree[v]==0)
{
tmp.id=v;
if(mp2[v]!=-2) tmp.val=ary[mp2[v]];
else tmp.val=-1;
que.push(tmp);
}
}
}
if(cnt<num) printf("-1\n");
else
{
if(cnt==0) printf("\n");
else
{
for(i=0;i<cnt;i++)
{
printf("%d",ans[i]);
if(i<cnt-1) printf(" ");
else printf("\n");
}
}
}
}
int main()
{
int t,i,p,gou,flag;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
pre[n]=0;
for(i=0;i<n;i++)
{
scanf("%d",&ary[i]);
if(ary[i]==-1) pre[i]=1;
else pre[i]=0;
}
for(i=0;i<n;i++)
{
if(i!=0) pre[i]+=pre[i-1];
}
for(i=1;i<=4*n;i++)
{
first[i]=-1;
degree[i]=0;
mp2[i]=-1;
}
num=0,tot=0;
build(0,n-1,1);
flag=1;
for(i=0;i<n;i++)
{
if(ary[i]==-1) continue;
p=ary[i]%n;
if(p<i)
{
if(p==0) gou=0;
else gou=pre[p-1];
if(pre[i-1]-gou>0)
{
flag=0;
break;
}
update(p,i-1,i,0,n-1,1);
}
else if(p>i)
{
if(pre[i-1]+pre[n-1]-pre[p-1]>0)
{
flag=0;
break;
}
update(p,n-1,i,0,n-1,1);
if(i>0) update(0,i-1,i,0,n-1,1);
}
}
if(flag) toposort();
else printf("-1\n");
}
return 0;
}