题目链接: J Hash Function
题目大意
一张hash表,长度为n,哈希函数为hash(x) = x mod n,如果有冲突,则位置向后移一位(n-1的下一位是0)
现在给你一张hash表,要求出字典序最小插入顺序
思路
如果a[i]%n != i,说明在a[i]插入前,a[i]%n到i-1所在的位置已经被占用了,也就是说区间[a[i]%n, i-1]中的数字必须在a[i]之前插入,处理出所有这样的情况,建图,如果a[u]必须在a[v]之前插入,那么连一条u到v的边,然后拓扑排序
但这样最坏可能有n^2的边,图太大了,但可以发现,建边都是一个区间[a[i]%n, i-1]向一个点i建边,那么可以利用线段树的思想,将所有节点建成一个线段树,将线段树中的子节点向父节点建边,这样就可以快速的将一个区间与一个点建边了
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int maxn = 2e5 + 100;
int n, a[maxn], T, pre[maxn];
int pos[maxn << 2], id[maxn << 2], in[maxn << 2];
vector<int> G[maxn << 2];
#define ls l, m, rt<<1
#define rs m+1, r, rt<<1|1
void addedge(int u, int v)
{
G[u].push_back(v);
in[v]++;
}
void build(int l = 0, int r = n - 1, int rt = 1)
{
id[rt] = -1;
if (l == r)
{
pos[l] = rt;
id[rt] = l;
return ;
}
int m = (l + r) >> 1;
addedge(rt<<1, rt);
addedge(rt<<1|1, rt);
build(ls);
build(rs);
}
void addedge(int L, int R, int p, int l = 0, int r = n - 1, int rt = 1)
{
if (L <= l && r <= R)
{
addedge(rt, p);
return ;
}
int m = (l + r) >> 1;
if (L <= m) addedge(L, R, p, ls);
if (m < R) addedge(L, R, p, rs);
}
bool check(int s, int t)
{
if (s <= t) return (pre[t] - pre[s] == 0) && (a[s] != -1);
return pre[t] == 0 && pre[n - 1] - pre[s - 1] == 0;
}
int main()
{
for (scanf("%d", &T); T; --T)
{
scanf("%d", &n);
for (int i = 0; i < n; ++i) scanf("%d", a + i);
for (int i = 0; i <= n * 4; ++i) G[i].clear(), in[i] = 0;
for (int i = 0; i < n; ++i) pre[i] = i ? (a[i] == -1) + pre[i - 1] : (a[i] == -1);
bool flag = 0;
for (int i = 0; i < n; ++i)
{
if (a[i] != -1 && !check(a[i] % n, i))
{
flag = 1;
break;
}
}
if (flag)
{
puts("-1");
continue;
}
build();
for (int i = 0; i < n; ++i)
{
if (a[i] != -1)
{
int s = a[i] % n, t = i;
if (s == t) continue;
else if (s < t) addedge(s, t - 1, pos[i]);
else
{
if (t != 0) addedge(0, t - 1, pos[i]);
addedge(s, n - 1, pos[i]);
}
}
}
priority_queue<P, vector<P>, greater<P>> que;
for(int i=0; i<n; ++i)
{
if(in[pos[i]] == 0) que.push(P(a[i], pos[i]));
}
vector<int> ans;
while(!que.empty())
{
P now = que.top(); que.pop();
int u = now.second;
if(now.first != -1) ans.push_back(now.first);
for(int v : G[u])
{
--in[v];
if(in[v] == 0) que.push(P(id[v]==-1 ? -1 : a[id[v]], v));
}
}
int len = ans.size();
if(len != n-pre[n-1])
{
puts("-1");
}
else
{
for(int i=0; i<len; ++i)
{
printf("%d%c", ans[i], i==len-1 ? '\n' : ' ');
}
if(len == 0) puts("");
}
}
return 0;
}