2021牛客暑假多校第二场 K题—Stack
题意:
一个单调栈,给你第n次操作时里面数据的数量,让你给出里面塞入的会是哪些数字。
主要思想:链表模拟
(代码里面有注释)
(题解一开始说的是拓扑,后来标程给的是链表,发现链表更加容易理解一些)
题目传送门
(题面粘贴过来比较难看,就不贴了)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<cstring>
#include<list>
#include<map>
#include<cstdio>
typedef long long ll;
typedef int64_t s64;
using namespace std;
const int maxn=1e6+5;
//解题思路:链表
int n,m;
int l[maxn],r[maxn],b[maxn]; //l数组代表改数左边是谁 l[1]=2就是1的左边是2
//同理 r数组代表改数左边是谁
//b数组就是题中给的那个b
int stk[maxn]; //模拟栈的数组
void link(int a,int b){
l[b]=a;r[a]=b; //用于链表的连接
}
int ans[maxn];
void solve(){
link(0,n+1); //给了这个链表头和尾 头是0 尾是6
int pos=1,ns=0; //ns 表示是栈里第几个 pos是当前第几个数即是当前的数
//(这个pos可能暂时不是很理解但继续读下去可能会慢慢明白)
for(int i=1;i<=n;i++){ //开始跑b数组
if(b[i]==-1) continue; //当没有给定的时候直接跳过(在主函数里会给b数组全部赋值为-1 当进来其他数时才会更改)
if(b[i]<1||b[i]>i) {cout<<-1<<endl;return;} //非法情况(即是小于1或者大于当前可容纳最多的)
if(b[i]-ns>i-pos+1) {cout<<-1<<endl;return;} //非法情况(即是当前需要增加的个数大于了我剩余可以给的个数)
//可以理解为我给了你所有的数都不够满足你的要求(没错就是在骂你贪心 你这个贪心怪!)
while(pos<=i){ //判断当前第几个数(pos)是否小于当前栈可以给的最多个数(i)
//(这里说的不是很清楚你们草稿纸模拟一下试试 但是你们要坚强不可以哭 不明白就来问我我帮你们用手模拟)
if(ns<b[i]){ //当前栈中的元素个数小于我们需要的,因为是小于的所以按照顺序正常添加即可
link(pos,r[stk[ns]]); // 当前数连接我栈顶的右边一个(这里要注意我们一开始那个6没有进栈哦 所以第一次连接的话栈顶(0)右边一个数就是6)
link(stk[ns],pos); //栈顶数再连接我当前数
stk[++ns]=pos; //ns++就是栈中数据个数加一 然后当前位置的数变为栈顶
}
else{ //当前栈中的元素个数大于我们需要的,因为是大于的所以要往前插入
ns=b[i]-1; //每次就往前一个插入直到我们满足要求为止
link(pos,r[stk[ns]]); //此处连接同上 就是连接位置不一样要注意
link(stk[ns],pos); //此处也同上
stk[++ns]=pos; //此处更是同上 (这次题解写的我自己都觉得拗口)
}
++pos; //当前第几个数往后一个
}
}
while(pos<=n){ //当整个循环结束当前数还是小于n 我们就把他正常插入填满就好 就是和当前栈中元素小于我们所需时候一样插入
link(pos,r[stk[ns]]); //同上
link(stk[ns],pos); //同上
++pos; //同上
}
for(int i=r[0],cnt=1;i<=n;i=r[i],cnt++){ //从第一个开始往后找自己右边那个(就是把链表跑一边并且呈现在ans中)
ans[i]=cnt;
}
for(int i=1;i<=n;i++){
i==1?cout<<ans[i]:cout<<" "<<ans[i]; //输出
}
cout<<endl;
}
int main(){ //主函数里面大部分就是题目要求的输入啦 写到这里你就要ac啦!
cin>>n>>m;
for(int i=1;i<=n;i++){
b[i]=-1;
}
int x;
for(int i=1;i<=m;i++){
cin>>x;
cin>>b[x];
}
solve();
return 0;
}
//加油!你又补完一题啦!
加油加油!!