單調棧學習筆記

第一題

題目描述

約翰有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;
}
相關文章
相關標籤/搜索