题目:
题意:
已知哈希函数为 hash(x) = x mod n ,如果出现哈希冲突,则 hash(x) = hash(x+1),直到没有冲突为止,现给出一张 hash 表,输出字典序最小的插入顺序
分析:
如果x不在hash(x)的位置上,那么hash[x]到x所在位置所有的数一定比x先插入,容易想到建图跑拓扑排序即可,但直接建图复杂度N^2,因为是一段区间上的点到点的建边,考虑将这段区间映射到线段树上的一个点,将线段树上每个节点与其父亲连一条单向边(两个儿子过了才能到父亲),建边时找到对应节点建边即可,注意:可能区间不合法,也就是区间没填满,用前缀和判断,最小字典序优先叶子节点的值就好了
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6+255;
int tr[maxn<<2],a[maxn],sum[maxn],T,n;
struct edge{
int to,nxt;
}e[maxn<<2];
int head[maxn<<2],cnt,pos[maxn<<2],val[maxn<<2],in[maxn<<2],vis[maxn<<2],num;
inline void add(int u,int v){
e[++cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
in[v]++;
}
void build(int l,int r,int x){
num++; val[x] = -1; vis[x] = 1; //num记录总结点的个数,vis标记那些节点使用了
if(l == r){
pos[l] = x;
val[x] = a[l];
return ;
}
int mid = (l+r) >> 1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
add(x<<1,x);add(x<<1|1,x);
}
void Updata(int l,int r,int L,int R,int x,int u){
if(L > R) return;
if(l > R || r < L) return ;
if(l >= L && r <= R){
add(x,u);
return ;
}
int mid = (l+r) >> 1;
Updata(l,mid,L,R,x<<1,u);
Updata(mid+1,r,L,R,x<<1|1,u);
}
struct node{
int x;
friend bool operator <(node a,node b){
return val[a.x] > val[b.x];
}
};
vector<int> ans;
bool spafa(){
priority_queue<node> q;
int sum = 0;
for(int i = 1;i <= (n<<2); ++i) if(!in[i]&&vis[i]) q.push(node{i});
while(!q.empty()){
node u = q.top();q.pop();
sum++;
if(~val[u.x]) ans.push_back(val[u.x]);
for(int i = head[u.x]; i;i = e[i].nxt){
int v = e[i].to;
if(--in[v] == 0) q.push(node{v});
}
}
return sum == num;
}
void init(int n){
ans.clear();cnt = num = 0;
for(int i = 0;i <= (n<<2); ++i)
head[i] = vis[i] = in[i] = 0;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
init(n);
for(int i = 1;i <= n; ++i) scanf("%d",a+i);
for(int i = 1;i <= n; ++i){
sum[i] = sum[i-1];
if(~a[i]) sum[i]++;
}
build(1,n,1); bool flag = true;
for(int i = 1;i <= n && flag; ++i){
if(~a[i]){
int tep = a[i] % n + 1;
if(i > tep) {
Updata(1,n,tep,i-1,1,pos[i]);
if(sum[i-1]-sum[tep-1] != i-tep) flag = false;
}
else if(i < tep){
Updata(1,n,tep,n,1,pos[i]);
if(sum[n]-sum[tep-1] != n-tep+1) flag = false;
Updata(1,n,1,i-1,1,pos[i]);
if(sum[i-1] != i-1) flag = false;
}
}
}
if(flag&&spafa()){
for(int i = 0;i < (int)ans.size(); ++i) printf("%d ", ans[i]);
putchar('\n');
}
else puts("-1");
}
return 0;
}