線段樹一類特殊技巧!
引出:cf671c ultimate weirdness of an array
其實是考試題,改題的時候並不會區間取最值,區間求和,之後秉承著好好學習的態度,學習了segment tree beats
套路是維護出區間最小值和次小值,以及區間最小值數量。之後再維護出題目中需要的東西就好了。之後怎麼處理呢,如果我們需要維護出區間和x取max,那麼,如果x<=minn[rt],那麼直接return;如果x=minx[rt],那麼就遞迴處理子樹資訊。
什麼?你說它的時間複雜度?每次修改均攤o(nlogn)
什麼時候修改是o(n)呢,就是所有點的狀態大概接近於1,2,1,2,1,2,1,2,1,2...之後對3取max,這種情況下單次修改是o(n)的,但是修改完這次之後,不論下一次修改是什麼,都是o(1)的,並且,求和不會超過o(nlogn)
其實本質上,什麼拖累了時間複雜度呢?就是當區間中不同的元素特別多的時候,單次修改的時間複雜度會較為高昂,但是假設,我們修改了a個元素,那麼就相當於區間的集合中少了a-1個元素,並且我們知道這次修改最大是alogn的,那麼下一次修改就相當於少了a-1個不同元素,也就是說,假設沒有這次修改,下一次修改b個元素的話,那麼有了這次修改下一次就相當於修改了b-a+1個元素,那麼我們考慮將所有的修改操作的時間複雜度求和,接近於o(nlogn),但是,這並不完全,因為每次修改可能會導致某些區間的元素個數增加。那麼我們考慮會增加多少呢?因為所有修改的元素都修改成了乙個值,那麼就相當於有些區間的元素的個數多了1。那麼修改的時間複雜度就是期望上(qlogn+nlogn),但是其實並不會跑滿,而且實際效率很快。
那麼線段樹的題嘛,考慮加上區間修改等操作的時間複雜度。因為每次區間覆蓋的話,非常棒,取消了許多節點的獨立性,時間複雜度完全沒有問題!但是區間加的話假如乙個區間的是1,2,3,4,5,6,1,2,3,4,5,6之後針對前6個區間加6,那麼相當於增加了一倍的獨立點個數,但是反過來考慮,構成1,2,3,4,5,6,1,2,3,4,5,6需要這種特殊構造,而特殊構造耗費的運算元量是接近n級別的,那麼其實反過來考慮一下,時間複雜度沒有任何問題,因為,其實我們考慮,只有區間修改的時間複雜度,是logn,那麼為什麼是o(logn)的原因是因為打了lazy標記,那麼其實我們假裝這裡打了乙個lazy標記,那麼其實每次修改的節點只有log級別的,那麼其實a也只增加了log級別的存在,而每次pushdown增加的也只是logn*alogn其實也就是alognlogn的時間複雜度。這非常正確,請不要反駁我。
那麼我們考慮完時間複雜度了,是不是該講題了?
並不是,因為例題沒有那麼多...
那麼我們先舉乙個例子
給定乙個長度為n的數列a,接下來有m次操作:
• 區間[l,r]中的所有數變成min(ai,x)
• 詢問區間[l,r]中所有數的和
• n,m≤50000 分塊!(抱歉,我不會!)
• n,m ≤ 500000
裸題,按照上述要求維護一下就可以了,如果想寫的話,可以聯絡我,我這裡有我自己出的資料...
給定乙個長度為n的數列a,接下來有m次操作:
• 區間[l,r]中的所有數變成min(ai,x)
• 區間[l,r]中的所有數加上x(x可能是負數)
• 詢問區間[l,r]中所有數的和
• n,m≤50000 分塊!
• n,m ≤ 500000
剩下的就是例題時間了!
這個是不是有一點感覺了呢?
分析:其實還是區間操作裸題,我們對於操作1,之間區間覆蓋,對於操作2先區間加,再區間取max...其實並不是很難對不對?對於操作3,之間輸出1-n的最小值個數(如果最小值是0的話)
附上**:
#include #include #include #include #include #include #include using namespace std;
#define n 300505
#define ls rt<<1
#define rs rt<<1|1
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
ll minn[n<<2],minx[n<<2],cn[n<<2],cov[n<<2],add[n<<2];int n,q;
void pushup(int rt)
void build(int l,int r,int rt)
int m=(l+r)>>1;build(lson);build(rson);pushup(rt);
}void update_cov(int l,int r,ll c,int l,int r,int rt)
pushdown(r-l+1,rt);int m=(l+r)>>1;
if(l<=m)update_cov(l,r,c,lson);if(m>1;
if(l<=m)update_add(l,r,c,lson);if(mc)pushdown(r-l+1,rt);int m=(l+r)>>1;
if(l<=m)update_max(l,r,c,lson);if(m>1;ll ret=0;
if(l<=m)ret+=query(l,r,lson);if(m好吧好吧...其實例題目前只有一道...目測還有最假女選手什麼的...好麻煩的說...
區間最值問題
實驗任務 已知乙個有 n 個數序列 a i 在序列 a 中的區間 l,r 中的最小值為 a p 求 a p a l a l 1 a r 的最大值為多少?資料輸入 第一行是乙個整數 n 第二行為 n 個整數對應 a i 對於 50 資料 1 n 5000 對於 100 資料 1 n 100 000 1...
區間最值問題
問題描述 給定m及n個數 1輸出每m個數中的最大數,即1m中的最大數,2m 1中的最大數 n m 1 n中的最大數,共n m 1個。陣列 將讀入的資料放到乙個線性表f陣列中,然後列舉開始點i,遍歷求出區間 i,i m 1 中最大值。堆 將資料組織成樹型結構,即將讀入的數值設計成乙個大根堆,則堆頂元素...
RMQ 區間最值 模板
rmq 的全稱為range max min query。構造dp陣列的時間為o nlogn 但是查詢時間為o 1 所以當資料量小於logn時,用樸素遍歷找最值就好,但是請求次數大於logn時,就要用這個模板。利用動態規劃的思想。int order maxn 使每乙個2 order i i 2 ord...