一維RMQ問題題集

2021-09-27 23:57:47 字數 4631 閱讀 9275

書本配套oj

本校oj

st表使用說明:

數列區間最大值

題意簡述

輸入一串數字,給你 m 個詢問,每次詢問就給你兩個數字 x,y,要求你說出 x 到 y 這段區間內的最大數。

解題思路

st表模板題。

**示例

#include

using

namespace std;

int n,m;

const

int n =

1e5+10;

int st[n][22

],log[n]

;int a[n]

;int

getint()

void

init()

}}intask

(int l,

int r)

intmain()

return0;

}

最敏捷的機械人

題意簡述

wind 設計了很多機械人。但是它們都認為自己是最強的,於是,一場比賽開始了……

機器人們都想知道誰是最敏捷的,於是它們進行了如下乙個比賽。首先,他們面前會有一排共 n 個數,它們比賽看誰能最先把每連續 k 個數中最大和最小值寫下來,當然,這些機械人運算速度都很快,它們比賽的是誰寫得快。

但是 wind 也想知道答案,你能幫助他嗎?

解題思路

st表模板題,不過還要維護一下最小值,多開乙個陣列即可。

**示例

#include

using

namespace std;

int n,m;

const

int n =

1e5+10;

int st[n][22

],log[n]

, st2[n][22

];int a[n]

;int

getint()

void

init()

}}void

ask(

int l,

int r)

intmain()

與眾不同*

題意簡述

a 是某公司的 ceo,每個月都會有員工把公司的盈利資料送給 a,a 是個與眾不同的怪人,a 不注重盈利還是虧本,而是喜歡研究「完美序列」:一段連續的序列滿足序列中的數互不相同。

a 想知道區間 [l,r] 之間最長的完美序列長度。

解題思路

我們可以通過標記陣列在o(n)時間內求出每個位置「作為結束位置」時的最長完美序列長度,以及它的起點。

設last[ x ] 表示 x 上次出現的位置;bgn[ p ]表示以位置 p 為末尾的完美序列的起點位置;len[p] 表示以位置 p 為末尾的完美序列的長度。顯然我們可以在一次遍歷內更新完畢上述三個陣列,o(n)。

那麼對於任意區間[ l , r ],其內的最長完美序列長度僅有 2 種可能,一種是終點在區間內,起點不在;另一種是起點和終點都在區間內。此時我們已經可以通過一次遍歷來求答案了,但是複雜度最差o(n),不可取。由於bgn是單調遞增的,所以對於某個位置 pos,[ l , pos-1] 所有位置上的起點都小於 l,[pos , r]上所有位置上的起點都大於l,那麼我們可以通過st表維護 [pos ,r] 上的最大的 len 值,在o(1)時間內求出,那麼答案就是max(pos-l , ask(pos , r) )。

我們可以通過二分搜尋來查詢 pos ,複雜度 o(log n),根據len陣列構造st表,o(nlogn),總時間複雜度o( (n+m)logn )。

**示例

#include

using

namespace std;

int n,m;

const

int n =

2e5+10;

const

int sz =

2e6+10;

const

int b =

1e6;

/*last[x]為x上一次出現的位置;

bgn[p]為以位置p結尾的起點位置;len[p]為以p結尾的完美序列長度*/

int last[sz]

,bgn[n]

,len[n]

;int a[n]

,log[n]

,st[n][22

];void

init_st()

intask

(int l,

int r)

intbsearch

(int l,

int r,

int x)

return l;

}void

solve()

init_st()

;//建立len陣列的st表

for(

int i =

1,x,y,p,res;i <= m;i++)}

intmain()

天才的記憶

**示例:模板模板,題面和思路不說了。

#include

using

namespace std;

int n,m;

const

int n =

2e5+10;

int st[n][22

],log[n]

;int a[n]

;int

getint()

void

init()

}}intask

(int l,

int r)

intmain()

return0;

}

balanced lineup

**示例:和「敏捷的機械人」一樣,都是要維護最大以及最小值。

#include

using

namespace std;

int n,m;

const

int n =

1e5+10;

int st[n][22

],log[n]

, st2[n][22

];int a[n]

;int

getint()

void

init()

}}void

ask(

int l,

int r)

intmain()

return0;

}

選擇客棧*

題意描述

麗江河邊有 n 家很有特色的客棧,客棧按照其位置順序從 1 到 n 編號。

每家客棧都按照某一種色調進行裝飾(總共 k 種,用整數 0 k−1 表示),且每家客棧都設有一家咖啡店,每家咖啡店均有各自的最低消費。

兩位遊客一起去麗江旅遊,他們喜歡相同的色調,又想嘗試兩個不同的客棧,因此決定分別住在色調相同的兩家客棧中。

晚上,他們打算選擇一家咖啡店喝咖啡,要求咖啡店位於兩人住的兩家客棧之間(包括他們住的客棧),且咖啡店的最低消費不超過 p 。

他們想知道總共有多少種選擇住宿的方案,保證晚上可以找到一家最低消費不超過 p 元的咖啡店小聚。

解題思路

沒看正解是啥,我沒用到st表,不過倒是用到了求rmq的步驟。

共三個輔助陣列,col[k] 表示當前第k種顏色客棧的數量;val[x]表示客棧x的最低消費;mip[x]表示 [x, n] 內第乙個最低消費小於等於 p 元的客棧位置。

如果第乙個人入住客棧x,第二個人能夠入住的旅店的位置一定是大於等於mip[x]的,並且要顏色和 x 相同,即col[ a[i] ]種選擇方案。所以我們只需要從前往後順序遍歷一遍並統計答案即可,複雜度o(n)。

**示例

#include

using

namespace std;

const

int n =

2e6+10;

const

int k =

1e4+10;

typedef

long

long ll;

int col[k]

;int n,m,p;

int a[n]

,val[n]

;int

getint()

int mip[n]

;void

solve()

int pre =

1; ll ans =0;

for(

int i =

1;i <= n;i++

)printf

("%lld\n"

,ans);}

intmain()

solve()

;return0;

}

二維RMQ問題

前置知識 一維rmq及其拓展 對於乙個n m n m的矩陣,每個格仔有乙個值,有q q個詢問,每次詢問你乙個子矩陣中的最大值。1 n,m 500,q 1061 n,m 500 q 1 06每次花子矩陣大小的複雜度去查詢。複雜度最壞o q n m o q n m 我們用n n棵線段樹或者樹狀陣列來維護...

關於RMQ問題的一些感悟

一般就是4種解決辦法吧。1 線段樹 2 樹狀陣列 3 st表 4 差分 樹狀陣列是一種很輕便的工具,編碼簡單,常數小,缺點是只能求和。不同版本的樹狀陣列能實現不同組合的單點,區間,詢問,修改。時間複雜度都是o logn st表也是一種很輕便的工具,編碼簡單,常數小,缺點是只能求最值,而且是離線演算法...

面試易錯題 陷阱題集一

1.oj 設計乙個函式sum n 1 2 n,假設sum n 不超過整型數表示範圍。錯誤解法 int sum n 錯誤在於 n n 1 時可能已經超出了整型數的表示範圍,造成溢位錯誤。int sum n 2.美圖 請寫出下面程式的執行結果。void func void printf s dst 易錯...