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;
}

浙公网安备 33010602011771号