1. 程式人生 > >樹狀數組維護區間最值

樹狀數組維護區間最值

%d 修改 stdio.h sin names ont eset soft html

在區間求和時,我們只需求出 [1, r][1,l?1],利用前綴和的可減性,得到區間 [l,r] 的和。

但區間最值不滿足這個性質。

我們可以把區間 [l,r] 拆分成若幹個子區間,再合並得到答案。

畫圖可知,max_i需要的 max 只有 max_{i-2^0}, max_{i-2^1}, max_{i-2^2} ... max_{i-lowbit(i)+1}。

修改

void change(int r) {
    c[r] = a[r];
    for(int i = 1; i < lowbit(r); i <<= 1)
        c[r] = max(c[r], c[r-i]);
}

查詢

我們找 [l, r] 的最值就是子區間最值的 max,即遞減 r,在這裏可以有個優化,即當找到一個 max_i??,有 i?lowbit(i)l 時,更

新後,i = i - lowbit(i),然後繼續遞減。當 l>r 就跳出循環。

int getmax(int l, int r) {
    int ret = a[r];
    while(l <= r) {
        ret = max(ret, a[r]);
        for(--r; r - l >= lowbit(r); r -= lowbit(r))
            ret 
= max(ret, c[r]); } return ret; }

需要指出的是,它只支持末端插入,不支持單點修改操作。

技術分享

技術分享

#include<iostream>
#include<stdio.h>
#include<memory.h>
using namespace std;
int A[200005];
int C[200005];
int lowbit(int x)
{
    return x&(-x);
}

void update(int x)
{
    C[x]=A[x];
    for(int i=1; i<lowbit(x); i<<=1
) C[x]=max(C[x],C[x-i]); } int query(int l,int r) { int ans=A[r]; while(l<=r) { ans=max(ans,A[r]); for(--r; r-l>=lowbit(r); r-=lowbit(r)) ans=max(ans,C[r]); } return ans; } int main() { int m,d; scanf("%d%d",&m,&d); int cnt = 0,t=0; for(int i = 0; i<m; i++) { char op; int n; scanf(" %c%d",&op,&n); if(op==A) { int temp = (n+t)%d; A[++cnt]=temp; update(cnt); } else { printf("%d\n",t = query(cnt-n+1,cnt)); } } return 0; }

樹狀數組維護區間最值