牛客网暑期ACM多校训练营(第四场)J Hash Function 拓扑排序 线段树

题目链接: 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 
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_queuevector

, greater

> que; for(int i=0; iif(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; iprintf("%d%c", ans[i], i==len-1 ? '\n' : ' '); } if(len == 0) puts(""); } } return 0; }

你可能感兴趣的:(-----线段树,拓扑排序)