關於動態最大子段和--線段樹查詢


question:

有n個數,a[1]到a[n]。

接下來q次查詢,每次動態指定兩個數l,r,求a[l]到a[r]的最大子段和。

子段的意思是連續非空區間。

輸入描述  Input Description

第一行一個數n。

第二行n個數a[1]~a[n]。

第三行一個數q。

以下q行每行兩個數l和r。

輸出描述  Output Description

q行,每行一個數,表示a[l]到a[r]的最大子段和。

樣例輸入  Sample Input

7
2 3 -233 233 -23 -2 233
4
1 7
5 6
2 5
2 3

樣例輸出  Sample Output

441
-2
233
3

 

高效完成這個問題,可以用線段樹進行區間動態查詢最大字段和

 

最大字段和

線段樹實現

線段樹維護:

 1. 區間最大字段和

 2. 從該區間的左端點開始的最大字段和(一定包括該區間左端點)

 3.   從該區間的右端點開始的最大字段和(同理一定包括該區間右端點)


最大字段和分布

 1. 完全的包含於做區間

 2. 完全的包含於右區間

 3. 包含於左右區間

維護的2,3主要是用於處理分布為3的情況

合並:很好理解

查詢:

當查詢區間完全處於當前區間的左側

  查詢當前區間的左兒子

當查詢區間完全處於當前區間的右側

  查詢當前區間的由兒子

否則說明查詢區間包含當前區間的mid

  將ans等置為0,從當前區間的左右兒子開始查詢

 會在3個黑圈處執行區間完全包含

從左到右依次編號1,2,3

會在1,2號return后進行一次ans, l_ans, r_ans 的賦max值

會在3好return后進行行一次ans, l_ans, r_ans 的賦max值

當遞歸到2,3節點時(注意這里是節點),進行一次

ans = max(max(L_ans, R_ans), L_rans + R_lans);
l_ans = max(l_ans, T[jd << 1].w + R_lans); 
r_ans = max(r_ans, T[jd << 1 | 1].w + L_rans);

結束后ans即為answer

#include <iostream>
#include <cstdio>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;
const int N = 4e6 + 1;

#define LL long long
#define zero 0

struct Node{
    int l, r, w, max, l_max, r_max;
};
Node T[N];
int n, m;

struct R{
    inline int reint(){
        int x = 0, f = 1; char c = getchar();
        while(c < '0' || c > '9'){
            if(c == '-') f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    inline LL rell(){
        LL x = 0, f = 1; char c = getchar();
        while(c < '0' || c > '9'){
            if(c == '-') f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
}re;

void un(int jd){
    T[jd].max = max(max(T[jd << 1].max, T[jd << 1 | 1].max), T[jd << 1].r_max + T[jd << 1 | 1].l_max);
    T[jd].l_max = max(T[jd << 1].l_max, T[jd << 1].w + T[jd << 1 | 1].l_max);
    T[jd].r_max = max(T[jd << 1 | 1].r_max, T[jd << 1 | 1].w + T[jd << 1].r_max);
    T[jd].w = T[jd << 1].w + T[jd << 1 | 1].w;
    return ;
}

void build_tree(int l, int r, int jd){
    T[jd].l = l;
    T[jd].r = r;
    if(l == r){
        T[jd].w = re.reint();
        T[jd].l_max = T[jd].r_max = T[jd].max = T[jd].w;
        return ;
    }
    int mid = (l + r) >> 1;
    build_tree(l, mid, jd << 1);
    build_tree(mid + 1, r, jd << 1 | 1);
    un(jd);
}

void Q_ask(int l, int r, int jd, int x, int y, LL & ans, LL & l_ans, LL & r_ans){
    if(x <= l && r <= y){
        ans = T[jd].max;
        l_ans = T[jd].l_max;
        r_ans = T[jd].r_max;
        return ;
    }
    int mid = (l + r) >> 1;
    if(y <= mid) Q_ask(l, mid, jd << 1, x, y, ans, l_ans, r_ans);
    else if(x > mid) Q_ask(mid + 1, r, jd << 1 | 1, x, y, ans, l_ans, r_ans);
    else{
        LL L_ans,L_lans, L_rans, R_ans, R_lans, R_rans;
        L_ans = L_lans = L_rans = R_ans = R_lans = R_rans = zero;
        Q_ask(l, mid, jd << 1, x, y, L_ans, L_lans, L_rans);
        Q_ask(mid + 1, r, jd << 1 | 1, x, y, R_ans, R_lans, R_rans);
        ans = max(max(L_ans, R_ans), L_rans + R_lans);
        l_ans = max(l_ans, T[jd << 1].w + R_lans); 
        r_ans = max(r_ans, T[jd << 1 | 1].w + L_rans); 
    }
}

int main(){
    n = re.reint();
    build_tree(1, n, 1);
    m = re.reint();
    for(int i = 1; i <= m; i ++)
    {
        int x = re.reint();
        int y = re.reint();
        LL ans, l_ans, r_ans;
        ans = l_ans = r_ans = zero;
        Q_ask(1, n, 1, x, y, ans, l_ans, r_ans);
        printf("%lld\n", ans);
    }
    
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM