AGC001F Wide Swap [線段樹+拓撲排序]

Description:
給出一個排列p ,兩個元素可以交換當且僅當|pipj|=1|ij|>=k ,求p 的最小字典序。


Solution:
轉換一下,構造序列q ,qpi=i ,等價於求q 的最小字典序。
那麼現在考慮相對位置不變的兩個數。對於一對<i,j>i<j ,他們不能交換,當且僅當|qiqj|<k ,那麼把qi>qj 連一條邊。由於這個關係有傳遞性,所以離最近的一個連邊就行了。


#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章