アルゴリズム競争上級ガイド--- 0x43(線分ツリー)これらの質問に答えられますか?

トピック

ここに画像の説明を挿入

サンプル出力

5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2

入力サンプル

2
-1

回答

  1. シングルポイント変更、間隔クエリ、従来の線分ツリーの問題、通常、シングルポイント変更はレイジーマーク(プッシュダウン操作)を使用しないため、問題はより単純になります
  1. 線分ツリーの問題を実行するとき、通常、最初にノードの属性を決定し、次にそれを実行します。次に、ノードの属性は何ですか。最も基本的なのは、区間lの左端と右端です。 r。質問に必要な最大の連続フィールドとlmaxもあります。これら3つを使用して、子ノードから親ノードのlmaxを更新できるかどうかを検討する必要がありますが、明らかに不可能です。図を見ると、間隔を超えない場合は、最大化するだけで済みます。左息子と右息子のlmax。ただし、間隔の場合、親ノードのlmaxは、左息子の最大の接尾辞と右息子の最大の接頭辞の合計である必要があります。
    ここに画像の説明を挿入
  1. 次に、ノード属性はpermax、sufmaxを増やす必要があります。次に、新しく追加された属性について、子ノードを介して更新できますか。また、図に示すように、状況を分割する必要があります。属性の合計(間隔の合計)を追加しました。親ノードの間隔の合計は、左と右の息子の間隔の合計に等しいため、新しい属性を追加する必要はありません。もちろん、最大サフィックスは同じです。ここでは説明しません。 。この時点で、ノードの属性はすべて更新されます。
    ここに画像の説明を挿入
  1. ノードの属性が決定されている限り、残りのテンプレートを直接設定できます。詳細については、コードを参照してください。

コード

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>

using namespace std;
const int N = 5e5 + 10;

int n, m;
int w[N];

struct Node {
    
    
    int l, r;       //左右端点
    int tmax;      //最大连续子段和
    int premax;   //最大前缀和
    int sufmax;  //最大后缀和
    int sum;    //区间和
} tr[N * 4];

//更新节点信息的函数
void pushup(Node &u, Node &l, Node &r) {
    
    
    u.sum = l.sum + r.sum;
    u.premax = max(l.premax, l.sum + r.premax);
    u.sufmax = max(r.sufmax, r.sum + l.sufmax);
    u.tmax = max(max(l.tmax, r.tmax), l.sufmax + r.premax);
}

//由子节点更新父节点的信息
void pushup(int u) {
    
    
    pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

//建树
void build(int u, int l, int r) {
    
    
    if (l == r) tr[u] = {
    
    l, r, w[r], w[r], w[r], w[r]};
    else {
    
    
        tr[u] = {
    
    l, r};
        int mid = (l + r) >> 1;
        build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}

//单点修改
void modify(int u, int x, int v) {
    
    
    if (tr[u].l == x && tr[u].r == x) tr[u] = {
    
    x, x, v, v, v, v};
    else {
    
    
        int mid = (tr[u].l + tr[u].r) >> 1;
        if (x <= mid) modify(u << 1, x, v);
        else modify(u << 1 | 1, x, v);
        pushup(u);
    }
}


//区间查询
Node query(int u, int l, int r) {
    
    
    if (l <= tr[u].l && tr[u].r <= r) return tr[u];
    else {
    
    
        int mid = (tr[u].l + tr[u].r) >> 1;
        if (r <= mid) return query(u << 1, l, r);
        else if (l > mid) return query(u << 1 | 1, l, r);
        else {
    
    
            Node res;
            auto left = query(u << 1, l, r);
            auto right = query(u << 1 | 1, l, r);
            pushup(res, left, right);
            return res;
        }
    }
}

int main() {
    
    

    cin >> n >> m;
    for (int i = 1; i <= n; i++) scanf("%d", &w[i]);

    build(1, 1, n);

    while (m--) {
    
    
        int op, x, y;
        cin >> op >> x >> y;
        if (op == 1) {
    
    
            if (x > y) swap(x, y);
            cout << query(1, x, y).tmax << endl;
        } else {
    
    
            modify(1, x, y);
        }
    }
    return 0;
}

おすすめ

転載: blog.csdn.net/qq_44791484/article/details/113827997