• 栈学习笔记


    (Huge 栈)

    (huge认识一下)

    一种 线性 数据结构 , 栈的修改是按照 后进先出 的原则进行的, 因此又称 后进先出 (last in first out) 表 , 简称 LIFO[^释义]表


    (huge 基操)

    我们可以用 数组 方便の模拟一个栈 ↓

    • int stk[N]; 使用 cnt 代表栈中元素 , 同时也是栈顶下标
    • stk[++cnt] = x; 压栈
    • int u = stk[cnt]; 取栈顶
    • if(cnt) --cnt; 弹栈 , 注意越界问题 , cnt == 0 时不能继续弹出
    • cnt = 0; 清空栈

    **だが ** 但是.. STL是个好东西

    #include <stack> //头文件
    stack<typename> s; //定义
    s.size(); //返回栈中元素个数
    s.empty(); //栈为空则返回1, 否则返回0
    s.pop(); //删除栈顶元素但不返回值
    s.top(); //返回栈顶元素但不删除
    s.push(x); //在栈顶压入新元素x
    //支持赋值运算符 =
    
    //顺手把队列的也放这里好了
    #include <queue>
    queue<typename> q;
    q.size(); //队列元素个数
    q.empty(); //队列为空返回true, 否则返回false
    q.pop(); //删除队首元素但不返回值
    q.front(); //返回队首元素但不删除
    q.push(); //在队尾压入新元素
    q.back(); //返回队尾元素但不删除
    

    具体实现戳这 队列


    (Huge 单调栈)

    (huge 认识一下)

    满足 单调性 的栈结构。与单调队列相比,其只在一端进行进出。

    单调递增栈:栈中数据 出栈 的序列为单调递增序列

    单调递减栈:栈中数据 出栈 的序列为单调递减序列


    (huge 使用)

    (LARGE 插入)

    为了维护单调性 , 在插入一个元素时要弹出一些元素 , 并且弹出的元素保证最少

    栗如 → (1,3,5,7,9) , (1为栈顶 , 递增栈) , 现要插入 (6) , 弹出 (1,3,5) , 此时栈内元素为 (6,7,9)

    伪代码 ↓

    insert x
    while (!sta.empty() && sta.top() < x) 
        sta.pop();
    sta.push(x);
    

    一个非常非常非常基础的栗题→我是蒻题!!


    (huge 一些栗题)

    怎么可能只考栈呢,当然要和其他的奇怪的东西结合起来啊(大雾

    我找的都是用栈就能做的,当然也可以用别的比如dp...

    T116755 WJQ的矩形

    一道小水题 单调栈维护最大矩形面积,(棋盘制作的子问题)

    提示:十年OI一场空,不开龙龙见祖宗

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    stack<ll> s;
    ll n, ans, o[100009];
    
    int main(){
    	std::ios::sync_with_stdio(0);
    	cin >> n;
    	s.push(0);
    	for(int i = 1; i <= n; i++) cin >> o[i];
    	for(int i = 1; i <= n; i++) {
    		while(s.size() > 1 && o[i] < o[s.top()]) {
    			int oo = s.top();
    			s.pop();
    			ans = max(ans, (ll)(o[oo] * (i - 1 - s.top()))); 
    		}
    		s.push(i);
    	}
    	while(s.size() > 1) {
    		int oo = s.top();
    		s.pop();
    		ans = max(ans, (ll)(o[oo] * (n - s.top())));
    	}
    	cout << ans;
    	return 0;
    } 
    

    P1169 [ZJOI2007]棋盘制作

    题目大意 : 给出 (N*M) 的 01 矩阵,分别找到一个 0 和 1 交错的矩形和一个正方形

    我们考虑枚举每一行,再枚举当前行的每个点,h数组表示当前点能向上延伸的最大长度(黑白相间),对于和前一个点不同颜色的点,进栈(维护一个栈的内部单增的栈),维护ans的最大值,如果遇到和前一个点颜色相同,则把栈都弹出,维护ans,顺手求一下正方形的面积就行了

    洛谷的样例太水了,这里给出一个同样水的样例 ↓

    6 6 
    1 0 0 1 0 1 
    0 1 1 0 0 1 
    0 0 0 1 0 0 
    1 1 1 0 1 0 
    0 1 0 1 0 0
    1 0 1 1 0 1  //输入
    
    9 
    10 //输出
    

    喜欢用STL,但自从考试有次T了之后就改用数组模拟了qwq,就不对本篇的STL做更改了

    #include <bits/stdc++.h>
    using namespace std;
    
    int n, m, F, J, x, y, h[2004];
    bool o[2004][2004];
    stack<int> s;
    
    int main() {
        std::ios::sync_with_stdio(false);
        cin >> n >> m; 
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                cin >> o[i][j]; 
        for(int i = 1; i <= n; i++){ //枚举行
            for(int j = 1; j <= m; j++){ //h数组的维护工作
                if(i > 1 && o[i][j] != o[i - 1][j]) h[j] ++;
                else h[j] = 1;
            } 
            int j = 1;  //j为当前点下标
            while(j <= m){ //边界
            	s.push(j - 1);
    			s.push(j++); //丢进第一个点
                while(j <= m && o[i][j] != o[i][j - 1]){ //若不超边且当前点和前一个不同
                    while(s.size() > 1 && h[j] < h[s.top()]){ //栈保留压底的0,当前点比栈顶小
                        x = h[s.top()]; //栈顶的高(矩形的长)
                        s.pop(); //栈顶弹出
                        y = j - 1 - s.top(); //矩形的宽
                        J = max(J, x * y); //矩形
                        F = max(F, min(x, y) * min(x, y)); //顺手来个正方形
                    }
                    s.push(j++); //当前点丢入
                }
                while(s.size() > 1){ //全都弹出 
                    x = h[s.top()];
                    s.pop();
                    y = j - s.top() - 1; 
                    J = max(J, x * y); 
                    F = max(F, min(x, y) * min(x, y));
                }
                s.pop();
            }
        }
        cout << F << endl << J;
        return 0;
    }
    

    看到这如果都懂了是不是觉得栈真(?)(?)是个好东西 (small嗝) ~

    P4147 玉蟾宫 双倍经验

    这个题改改上面那个代码的条件就行了

    P3551 [POI2013]USU-Take-out【征集 spj】(思维好题)

    题目大意 : 一排方块,白块个数是黑块的 (k) 倍,现要消除此序列,每次消除 (k+1) 块砖,其中 (k) 块白色 (biały) 1 块黑色 (czarny),消除的块之间不能有已经消除的块(看不明白就走一边样例

    从前到后用栈扫一遍就可以了,逆向想,在 (k+1) 的范围里出现一个黑块就可以消去了,记录在一个数组里,最后倒序输出就可以了

    #include<bits/stdc++.h>
    using namespace std;
    
    int n, k, top, c, cx[1000009], s[1000009], ans[1000009];    
    char o[1000009];
    
    int main() {
        cin >> n >> k >> o + 1;
        for(int i = 1; i <= n; i++){
            s[++top] = i; 
            cx[top] = cx[top - 1] + (o[i] == 'c');
            if(top >= (k + 1) && cx[top] - cx[top - k - 1] == 1)
                 for(int j =top - k - 1; j < top; top--) ans[++c] = s[top];
        }
        for(int i = n; i; i--) {
            cout << ans[i] << " ";
            if(i % (k + 1) == 1) cout << "
    ";
        }
        return 0;
    }
    

    end.

    而我们终其一生,都希望能成为更好的人。
  • 相关阅读:
    汇编语言--栈
    汇编语言--debug
    汇编语言--指令
    汇编语言--寄存器
    汇编语言--基本概念(来自王爽老师课程)
    python--IO模块(系统整理)(持续更新)
    python--python在传递参数时实际做了什么?(持续更)
    python--函数之python执行def和import时做了什么
    sql--常用命令(学习笔记,持续更新)
    sql-什么是sql脚本
  • 原文地址:https://www.cnblogs.com/moziii/p/13300806.html
Copyright © 2020-2023  润新知