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;
}
posted @ 2021-09-30 13:08  Bcoi  阅读(41)  评论(0)    收藏  举报