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;
} 
京公网安备 11010502036488号