2018牛客多校第四场 J.Hash Function

题意:

  给出一个已知的哈希表。求字典序最小的插入序列,哈希表不合法则输出-1。

题解:

  对于哈希表的每一个不为-1的数,假如他的位置是t,令s = a[t]%n。则这个数可以被插入当且仅当第s ~ t-1个数都不为-1且已经插入完成。

  那么对于每一个这样的数,需要连t-s条边(s<=t)或者t+n-s条边(s>t)。

  总的边数有O(n^2)条。可以用线段树优化建图。最后跑一边拓扑排序。

  对于不合法的情况,第s ~ t-1个数存在-1或者拓扑图存在环会导致不合法。

#include <bits/stdc++.h>
using namespace std;
#define P pair<int, int>
const int N = 4e5+10;
int t, n;
int cnt, tot;
int ans[N];
int a[N], pre[N];
int pos[N], rt[N<<2], deg[N<<2];
int head[N<<3], nxt[N<<3], to[N<<3];
priority_queue<P, vector<P>, greater<P> > q;
void add_edge(int u, int v) {
    to[++tot] = v;
    nxt[tot] = head[u];
    head[u] = tot;
    deg[v]++;
}
void build(int id, int l, int r) {
    rt[id] = -1;
    if(l == r) {
        pos[l] = id;
        rt[id] = l;
        return;
    }
    int mid = l+r>>1;
    build(id<<1, l, mid);
    build(id<<1|1, mid+1, r);
    add_edge(id<<1, id);
    add_edge(id<<1|1, id);
}
void update(int id, int l, int r, int ql, int qr, int v) {
    if(ql <= l && r <= qr) {
        add_edge(id, v);
        return ;
    }
    int mid = l+r>>1;
    if(ql <= mid) update(id<<1, l, mid, ql, qr, v);
    if(qr > mid) update(id<<1|1, mid+1, r, ql, qr, v);
}
int main() {
    scanf("%d", &t);
    while(t--) {
        tot = 0;
        scanf("%d", &n);
        memset(head, -1, sizeof(int)*(n<<3));
        memset(deg, 0, sizeof(int)*(n<<2));
        for(int i = 0; i < n; i++) {
            scanf("%d", &a[i]);
            pre[i] = a[i] == -1;
            if(i) pre[i] += pre[i-1];
        }
        int flag = 0;
        for(int i = 0; i < n; i++) {
            if(~a[i]) {
                int s = a[i]%n, t = i;
                if(s <= t && pre[t]-(s==0?0:pre[s-1]) || s > t && pre[t]+pre[n-1]-pre[s-1]) {
                    flag = 1;
                    break;
                }
            }
        }
        if(flag) {
            puts("-1");
            continue;
        }
        build(1, 0, n-1);
        for(int i = 0; i < n; i++) {
            if(~a[i]) {
                int s = a[i]%n, t = i;
                if(s < t) update(1, 0, n-1, s, t-1, pos[t]);
                if(s > t) {
                    if(t > 0) update(1, 0, n-1, 0, t-1, pos[t]);
                    update(1, 0, n-1, s, n-1, pos[t]);
                }
            }
        }
        P now;
        cnt = 0;
        while(!q.empty()) q.pop();
        for(int i = 0; i < n; i++) {
            if((~a[i]) && deg[pos[i]] == 0) q.push(make_pair(a[i], pos[i]));
        }
        while(!q.empty()) {
            now = q.top();
            q.pop();
            int u = now.second;
            if(~rt[u]) ans[++cnt] = now.first;
            for(int i = head[u]; ~i; i = nxt[i]) {
                if(--deg[to[i]] == 0) {
                    if((~rt[to[i]]) && (~a[rt[to[i]]])) q.push(make_pair(a[rt[to[i]]], to[i]));
                    else if(rt[to[i]] == -1) q.push(make_pair(0, to[i]));
                }
            }
        }
        if(cnt != n-pre[n-1]) {
            puts("-1");
            continue;
        }
        for(int i = 1; i <= cnt; i++) {
            printf("%d", ans[i]);
            if(i != cnt) printf(" ");
        }
        puts("");
    }
}
View Code
原文地址:https://www.cnblogs.com/Pneuis/p/9385563.html