P1440 求m區間內的最小值 題解

2022-02-14 17:18:10 字數 1281 閱讀 2661

csdn同步

原題鏈結

簡要題意:

給定 \(n\) 個數 \(\\) 和乙個 \(m\),輸出所有 \(1 \leq i \leq n\) 的 \(\min_^ a_i\).

\(n,m \leq 2 \times 10^6\).

顯然這就是對每個數求出其前 \(m\) 個數的最小值

樸素令 \(f_i = \min_^ a_i\),\(\mathcal(n^2)\) 炸的飛起。

當然你用線段樹,樹狀陣列,\(\text\) 來維護區間最小都是 \(\mathcal(n \log n)\) 的,不夠優,常數還不一定能過。

我們考慮如何從 \([l,r] \rightarrow [l+1,r+1]\) 即可。

用乙個佇列 \(q\),維護當前可能會影響答案的編號

什麼叫做可能會影響答案

比方說當前求的是編號 \(i\) 的答案,那麼顯然,編號 \(u就應該出隊,因為所以包括 \(i\) 在內之後的節點都不可能用到編號 \(u\) 來作為決策了

其次,如果存在 \(u\) 使得 \(u < i , a_u > a_i\),這時候你會發現,\(i\) 節點的價值比 \(u\) 更高。因為,\(i\) 節點及以後的點用 \(i\) 的次數比用 \(u\) 的次數多,而 \(i\) 的決策又始終比 \(u\) 優,那麼 \(u\) 就可以出隊了。

我們把當前區間的最小值編號始終放在第一位,以便取出。

時間複雜度: \(\mathcal(n)\).(每個點入隊一次,出隊一次)

實際得分:\(100pts\).

#pragma gcc optimize(2)

#includeusing namespace std;

const int n=2e6+1;

inline int read()

int x=0; while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f;}

inline void write(int x)

if(x<10)

write(x/10);putchar(char(x%10+'0'));

}int n,m,a[n],q[n];

int l=1,r=0;

int main()

return 0;

}

P1440 求M區間內的最小值

乙個含有 nn 項的數列,求出每一項前的 mm 個數到它這個區間內的最小值。若前面的數不足 mm 項則從第 11 個數開始,若前面沒有數則輸出 00。第一行兩個整數,分別表示 nn,mm。第二行,nn 個正整數,為所給定的數列 a ia i nn 行,每行乙個整數,第 ii 個數為序列中 a ia ...

P1440 求m區間內的最小值

乙個含有n項的數列 n 2000000 求出每一項前的m個數到它這個區間內的最小值。若前面的數不足m項則從第1個數開始,若前面沒有數則輸出0。輸入格式 第一行兩個數n,m。第二行,n個正整數,為所給定的數列。輸出格式 n行,第i行的乙個數ai,為所求序列中第i個數前m個數的最小值。輸入樣例1 627...

P1440 求m區間內的最小值

這道題就是經典的滑動視窗問題了。要求你求某乙個數的前 m 位中的最小元素。先說一句話 單調佇列中,隊首儲存的是最優解,其實是次解,以此類推。所以我們可以構造乙個上公升的單調佇列,隊首弄出來的就是答案。元素的加入不用說,就是那樣子。重點是這裡多了元素的刪除。因為視窗的長度有限,你需要把當前視窗沒有覆蓋...