2018牛客暑期多校J - Hash Function (线段树优化建边 + 拓扑排序)
思路:
考虑一个数\(a_i\)现在所处的位置\(cur\)和原本应该处于的位置\(pos\)之间的关系,既然\([cur,pos]\)的位置\(a_i\)都不能插入,那么就意味着,\([cur,pos]\)这些位置的数在哈希的插入序列中必须在当前这个数\(a_i\)的前面。
一些数在序列中的位置相对于其他一些数有要求,那么我们就可以想到拓扑排序,但是这是区间内的所有数对一个点同时连边,直接做时间复杂度肯定是不可以的,但是这个东西可以被线段树优化建图来解决,那么到此问题就解决了,优化建图后,直接拓扑即可。
对于题目中提到的\(-1\)的情况,有可能是无法形成拓扑序,再有一种可能就是题目原本的插入序列就是不合法的,即一个数当前的位置和它原本应该在的位置之间有若干个\(-1\)存在,这种情况也是-1。
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 2e6 + 10;
int n,a[N],tro[N],id[N],indegree[N];
std::vector<int>G[N];
void add(int u,int v) {
G[u].pb(v);
}
void build(int rt,int l,int r) {
id[rt] = indegree[rt] = 0;
if(l == r) {
id[rt] = l;
tro[l] = rt;
return ;
}
int mid = (l + r) >> 1;
build(lson,l,mid); build(rson,mid+1,r);
add(lson,rt); add(rson,rt);
indegree[rt]+=2;
}
void modify(int rt,int l,int r,int L,int R,int u) {
if(l >= L && r <= R) {
add(rt,u);
indegree[u]++;
return ;
}
int mid = (l + r) >> 1;
if(L <= mid) modify(lson,l,mid,L,R,u);
if(R > mid) modify(rson,mid+1,r,L,R,u);
}
int sum[N];
std::vector<int>ans;
void tuposort() {
ans.clear();
priority_queue<pii,vector<pii>,greater<pii> >q;
for(int i = 1;i <= n;i ++) {
if(a[i] == -1) continue;
if(indegree[tro[i]] == 0) {
q.push({a[i],tro[i]});
}
}
while(!q.empty()) {
int u = q.top().second;
q.pop();
if(id[u]) {
ans.pb(a[id[u]]);
}
for(auto v : G[u]) {
--indegree[v];
if(indegree[v] == 0) {
if(!id[v]) q.push({-1,v});
else q.push({a[id[v]],v});
}
}
}
}
void init() {
for(int i = 0;i <= n * 10;i ++) G[i].clear();
}
void solve() {
scanf("%d",&n);
for(int i = 1;i <= n;i ++) {
scanf("%d",&a[i]);
}
init();
for(int i = 1;i <= n;i ++) {
a[i] == -1 ? sum[i] = sum[i-1] + 1 : sum[i] = sum[i-1];
}
if(sum[n] == n) {
printf("\n"); return ;
}
// inittree(1,1,n);
build(1,1,n);
for(int i = 1;i <= n;i ++) {
if(a[i] == -1) continue;
int sd = a[i] % n + 1;
if(sd == i) continue;
if(sd < i) {
if(sum[i] - sum[sd-1] > 0) {
printf("-1\n"); return ;
}
modify(1,1,n,sd,i-1,tro[i]);
}
if(sd > i) {
if(sum[i] + sum[n] - sum[sd-1] > 0) {
printf("-1\n"); return ;
}
modify(1,1,n,sd,n,tro[i]);
if(i > 1) modify(1,1,n,1,i-1,tro[i]);
}
}
tuposort();
if(sz(ans) == n - sum[n]) {
for(int i = 0;i < sz(ans);i ++) printf(i == sz(ans) - 1 ? "%d\n" : "%d ",ans[i]);
}
else {
printf("-1\n");
}
}
int main() {
int T;scanf("%d",&T);
while(T--) solve();
return 0;
}