2021牛客暑假多校第二场 K题—Stack (链表)

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;
}
//加油!你又补完一题啦!

加油加油!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值