1. 程式人生 > 其它 >NC11253 K.Stack(貪心+拓撲排序)

NC11253 K.Stack(貪心+拓撲排序)

目錄

Description

有一個單調棧,棧頂最大,記 \(b[i]\)\(a[i]\) 放入棧中後,棧的大小,給出 \(m\)\(b[i]\) ,構造一個 \(a\) 陣列使得 \(b\) 陣列成立(\(a\) 為 $permutation $)

State

\(1<=n<=10^6\)

\(1<=m<=n\)

Input

5 2
2 2
5 4

Output

1 2 5 3 4

Solution

再加入一個元素後,棧內元素個數可以減很多,但是隻能增加一個;

所以如果 \(b[i]=0\)\(b[i]=b[i-1]+1\) 這樣貪心的選取,可以保證之後的 \(b[j]\) 存在

之後, \(b[i]>b[i-1]+1\) 那麼一定是不合法的

\(b[i]=b[i-1]+1\) ,說明 \(a[i]\) 只比棧頂元素小

\(b[i]<b[i-1]+1\), 那麼一直執行出棧操作,直到 \(b[i]=b[j]+1\),在整個過程中, \(a[i]\)

是最小的

我們可以根據大小關係建一個圖,\(i->j\) 表示 \(j>i\),然後拓撲排序,就可以得到答案了


Code

const int N = 1e6 + 5;
 
    int n, m, k, _;
    int a[N];
    int b[N];
    stack<pii> s;
    vector<int> v[N];
    int into[N];

void topsort()
{
    queue<int> q;
    for(int i = 1; i <= n; i ++){
        if(into[i] == 0) q.push(i);
    }
    int id = 1;
    while(q.empty() == false){
        int u = q.front();
        q.pop();
        a[u] = id ++;
        for(auto it : v[u]){
            into[it] --;
            if(into[it] == 0) q.push(it);
        }
    }
}

int main()
{
    //IOS;
    while(~ sdd(n, m)){
        int p, x;
        while(m -- > 0){
            sdd(p, x);
            b[p] = x;
        }
        for(int i = 1; i <= n; i ++){
            if(b[i] == 0) b[i] = b[i - 1] + 1;
        }
        int ok = 1;
        for(int i = 1; i <= n; i ++){
            if(b[i] - b[i - 1] > 1) ok = 0;
        }
        if(! ok){
            puts("-1");
            continue;
        }
        for(int i = 1; i <= n; i ++){
            while(! s.empty() && s.top().se >= b[i]){
                v[i].pb(s.top().fi);
                into[s.top().fi] ++;
                s.pop();
            }
            if(s.empty() == false){
                v[s.top().fi].pb(i);
                into[i] ++;
            }
            s.push({i, b[i]});
        }
        topsort();
        for(int i = 1; i <= n; i ++){
            printf("%d ", a[i]);
        }
    }
    //PAUSE;
    return 0;
}