单调栈学习笔记

第一题

题目描述

约翰有N头奶牛,编号为1到N。ios

如今这N头奶牛按编号从小到大的顺序站成了一排,其中奶牛 i 的身高为Hi。c++

如今,每头奶牛都向它的右侧望向那些编号较大的奶牛,对于奶牛 i 若是存在一头奶牛 j 知足 $i<j$ 而且 $H_i<H_j$,那么咱们称奶牛 i 须要仰视奶牛 j。算法

请你求出每头奶牛的最近仰视对象。安全

输入格式 第一行包含整数N。数据结构

接下来N行,每行包含一个整数$H_i$,其中第 i 行的数为编号为 i 的奶牛的高度。优化

输出格式 共 N 行,每行输出一个整数,其中第 i 行的输出整数表示编号为 i 的奶牛的最近仰视对象的编号,若是不存在仰视对象,则输出0spa

数据范围 $1 \le N \le 10^5$ $1 \le H_i \le 10^6$ 输入样例:code

6 
3 
2 
6 
1 
1 
2

输出样例:对象

3 
3 
0 
6 
6 
0

解题思路

题意分析

这道题目大体意思是:每一头奶牛往右看,找到离本身最近,并且比本身身高高的牛, 若是没有比本身高的牛,那么输出0便可.也就是无解判断ci

算法分析

首先咱们知道程序=数据结构+算法,这道题目算法,咱们除了暴力+模拟,实在想不到任何解题思路.多是我太蠢了

因此咱们考虑如何经过数据结构来优化这道题目.

数据结构

对于一道题目而言,咱们须要对于条件,性质两处地方动手,来思考算法或者数据结构的突破口,显然这道题目数据结构的肯定,一样离不开这条不定的定律.

对于这道题目而言,咱们主要是分析条件,由于咱们发现这道题目全部的奶牛,都在找离着本身最近的奶牛,那么咱们不得不思考,是否是要用到后进先出的栈

既然如今咱们已经肯定,数据结构大体为栈,那么如今咱们就须要分析性质了.

分析性质

这道题目,最有用的性质,就是离本身最近,并且比本身身高高.

  1. 离本身最近:这个性质其实就是咱们所谓的栈的必备性质.
  2. 身高高:看到这种类型的词汇,必定要第一时间反应,这道题目是否是拥有单调性.

通过上面的讨论,咱们大体能够肯定,这道题目的确拥有单调性,那么想让咱们的数据结构栈,就进化成为了单调栈.

算法整合

咱们能够一步步读入奶牛,对于每一头奶牛而言,判断这一头奶牛能够成为哪些奶牛的仰视对象. 因而,咱们能够将当前奶牛,不断地和栈顶奶牛比较,若是说它身高大于栈顶奶牛,那么栈顶奶牛的仰视对象必定是当前奶牛,而后将栈顶奶牛出栈,进行下一次比较,直到栈为空或者栈顶奶牛身高高于它.最后再将咱们当前奶牛的身高入栈.

之因此仰视对象是当前奶牛,由于它是离栈顶奶牛最近的奶牛,并且知足身高大于它.

能够略微证实一下,由于若是说栈顶奶牛的仰视对象不是当前这头奶牛,那么在这头奶牛以前,栈顶奶牛确定已经出栈了,由于必然在此以前,会有奶牛成为栈顶奶牛的仰视对象,然而如今它还在栈中,那么栈顶奶牛的仰视对象,必然是当前这头奶牛.

代码
#include <bits/stdc++.h>
using namespace std;
const int N=101000;
int n,m,i,j,k,a[N],s[N];
stack<pair<int,int> > q;
int main()
{
    ios::sync_with_stdio(false);//优化不可少
    cin>>n;
    for(int i=1; i<=n; i++)
        cin>>a[i];
    for(int i=1;i<=n;i++)
    {
        while (q.size() && a[i]>q.top().first)//栈内有奶牛,且身高大于栈顶的奶牛
        {
            s[q.top().second]=i;//仰视对象
            q.pop();
        }
        q.push(make_pair(a[i],i));//加入栈中
    }
    for(int i=1;i<=n;i++)
        cout<<s[i]<<endl;//输出便可
    return 0;
}

第二题

题目描述

某地有 N 个能量发射站排成一行,每一个发射站 i 都有不相同的高度 $H_i$,并能向两边(固然两端的只能向一边)同时发射能量值为 $V_i$ 的能量,而且发出的能量只被两边最近的且比它高的发射站接收

显然,每一个发射站发来的能量有可能被 0 或 1 或 2 个其余发射站所接受,出于安全考虑,每一个发射站接收到的能量总和是咱们很关心的问题。

因为数据不少,如今只须要你帮忙计算出接收最多能量的发射站接收的能量是多少。

输入格式 第一行包含整数N。

接下来N行,每行包含两个整数$H_i$和$V_i$,其中第 i 行的数据为第 i 个发射站的高度和能量值。

输出格式 输出仅一行,表示接收最多能量的发射站接收到的能量值。

数据保证答案不超过$2^{31}-1$。

数据范围 $1 \le N \le 10^6$, $1 \le H_i \le 2*10^9$, $1 \le V_i \le 10000$

输入样例:

3
4 2 
3 5 
6 10

输出样例:

7

解题思路

题意分析

N 个能量发射站排成一行,每一个发射站 i 都有不相同的高度 $H_i$,并能向两边同时发射能量值为 $V_i$ 的能量,而且发出的能量只被两边最近的且比它高的发射站接收。而后要咱们求出这个最大的接受能量值是多少.

思路分析

首先咱们知道程序=数据结构+算法,这道题目算法,咱们除了暴力+模拟,实在想不到任何解题思路.多是我太蠢了

因此咱们考虑如何经过数据结构来优化这道题目.

数据结构

既然如今咱们已经想到了数据结构来优化算法,那么如今当前最大的问题.无非就是如何利用这个咱们学过数据结构来优化这道题目.

咱们发现这道题目,全部的数字都知足一个很是重要的性质,那就是发出的能量只被两边最近的且比它高的发射站,咱们从中间,不但会发现这道题目的条件,还会发现这道题目出题人,偷偷告诉咱们的性质.那就是两边最近且比他高.

性质分析

两边最近: 显然,是一个条件&性质,并且这里面最为重要的性质核心,就是最近这个两个字.

看到这里,咱们就得让神经系统中的神经元,条件反射地想到,是否是须要后进后出的数据结构栈

比他高: 这就是这道题目的第二大精髓思想,单调性,咱们经过这道题目的这句话,能够敏锐地察觉到,这道题目须要使用具备单调性质的单调栈.

算法步骤

这道题目既然是须要使用具备很是秀的单调栈,那么咱们到底如何使用呢?

那么此时咱们就须要根据条件,来肯定单调栈,插入栈顶的条件.

由于对于一个发射站而言,它能够接收到的能量,就是一组单调递减的高度序列的能量.这里咱们须要画图解决问题.

综上所述,咱们能够开一个单调递减的栈,统计全部高度单调递减的发射站.

  1. 若是当前这个数字破坏了单调递减,那么它会挡掉比它矮的全部发射站. 而后将全部比它能量小的发射站,通通吸收.而后将这些发射站出栈,本身入栈.
  2. 若是当前发射站,知足单调递减的话,那么栈顶所属的发射站,吸收它的能量.一样本身也须要入栈
代码实现
#include <bits/stdc++.h>
using namespace std;
const int N=1001000;
pair<int,int> p[N];
int top,x,n,m,i,j,s[N],a[N],b[N],ans,top2;
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1; i<=n; i++)
        cin>>a[i]>>b[i];//读入
    p[++top].first=a[1];//first存储高度
    p[top].second=1;//存储这个发射塔的位置
    for(int i=2; i<=n; i++)
    {
        while (a[i]>p[top].first && top)
            s[i]+=b[p[top--].second];//将这个发射塔的能量吸收
        s[p[top].second]+=b[i];//栈顶吸取我这个发射塔的能量
        p[++top]=make_pair(a[i],i);//插入栈中
    }
    for(int i=1; i<=n; i++)
        ans=max(ans,s[i]);
    cout<<ans;
    return 0;
}
相关文章
相关标签/搜索