Description

有一个排列 , 令 表示 中满足 的个数,现在给出 个不重复的 ,问能否构造一个 排列 符合条件。

Solution

(这个做法感觉比拓扑排序好理解)
显然对于每一个 ,必须满足 ,那么对于未给出数值的 ,可以考虑先给它们填充上数值,不妨令 ,这样构造能够满足的条件,随后只需要从后往前构造即可。
从后往前构造时,假如当前 ,那么最理想的情况下是 ,但是可能在前面的构造里已经填充了 等值,所以需要用一个树状数组维护前面已经用的值,再二分找到符合条件的最小数值填到当前位置。例如 ,前面已经用了 ,那么 ,构造出来的样子就是

Code

#include<bits/stdc++.h>

const int mod = 1e9 + 7;
const int N = 1e6 + 5;

int a[N], b[N];
bool vis[N];
int T[N];

class Bit {
    public:
    int lowbit(int x) {
        return x & (-x);
    }
    Bit() {
        memset(T, 0, sizeof(T));
    }
    void update(int x, int add) {
        while (x < N) {
            T[x] += add;
            x += lowbit(x);
        }
    }
    int query(int x) {
        int res = 0;
        while (x) {
            res += T[x];
            x -= lowbit(x);
        }
        return res;
    }
};

void solve() {
    int n, k, ok = 1; std::cin >> n >> k;
    for (int i = 1; i <= k; i++) {
        int id, x; std::cin >> id >> x;
        b[id] = x;
        if (b[id] > id) {
            ok = 0;
        }
    }
    if (!ok) {
        std::cout << -1 << '\n'; return ;
    }
    Bit Tree;
    for (int i = 1; i <= n; i++) {
        Tree.update(i, 1);
    }
    for (int i = 1; i <= n; i++) {
        if (!b[i]) {
            b[i] = b[i - 1] + 1;
        }
        if (b[i] - b[i - 1] > 1) {
            std::cout << -1 << '\n'; return ;
        }
    }
    for (int i = n; i >= 1; i--) {
        int left = 1, right = n;
        int ans = -1;
        while (left <= right) {
            int mid = (left + right) >> 1;
            if (Tree.query(mid) >= b[i]) {
                ans = mid; 
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        a[i] = ans;
        Tree.update(ans, -1);
    }
    for (int i = 1; i <= n; i++) {
        std::cout << a[i] << " \n"[i == n];
    }
}

signed main() {
    std::cin.sync_with_stdio(false), std::cin.tie(nullptr);
    int T = 1; //std::cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}