Description:
給出一個排列 ,兩個元素可以交換當且僅當 且 ,求 的最小字典序。
Solution:
轉換一下,構造序列 , ,等價於求 的最小字典序。
那麼現在考慮相對位置不變的兩個數。對於一對 且 ,他們不能交換,當且僅當 ,那麼把 連一條邊。由於這個關係有傳遞性,所以離最近的一個連邊就行了。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 5, inf = 0x3f3f3f3f;
int n, k;
int mn[maxn * 4], p[maxn], in[maxn], ans[maxn];
vector<int> G[maxn];
int read() {
int x = 0, f = 1;
char c = getchar();
while(!isdigit(c)) {
if(c == '-') {
f = -1;
}
c = getchar();
}
while(isdigit(c)) {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
void update(int l, int r, int x, int p, int d) {
if(l == r) {
mn[x] = d;
return;
}
int mid = (l + r) >> 1;
if(p <= mid) {
update(l, mid, x << 1, p, d);
} else {
update(mid + 1, r, x << 1 | 1, p, d);
}
mn[x] = min(mn[x << 1], mn[x << 1 | 1]);
}
int query(int l, int r, int x, int a, int b) {
if(l > b || r < a) {
return inf;
}
if(l >= a && r <= b) {
return mn[x];
}
int mid = (l + r) >> 1;
return min(query(l, mid, x << 1, a, b), query(mid + 1, r, x << 1 | 1, a, b));
}
int main() {
n = read();
k = read();
memset(mn, inf, sizeof(mn));
for(int i = 1; i <= n; ++i) {
p[read()] = i;
}
for(int i = n; i; --i) {
int t = query(1, n, 1, p[i] + 1, min(p[i] + k, n));
if(t != inf) {
G[p[i]].push_back(p[t]);
++in[p[t]];
}
t = query(1, n, 1, max(1, p[i] - k + 1), p[i] - 1);
if(t != inf) {
G[p[i]].push_back(p[t]);
++in[p[t]];
}
update(1, n, 1, p[i], i);
}
priority_queue<int, vector<int>, greater<int> > q;
for(int i = 1; i <= n; ++i) {
if(!in[i]) {
q.push(i);
}
}
while(!q.empty()) {
int u = q.top();
ans[u] = ++ans[0];
q.pop();
for(int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
if(!--in[v]) {
q.push(v);
}
}
}
for(int i = 1; i <= n; ++i) {
printf("%d\n", ans[i]);
}
return 0;
}