Leetcode3165:不包含相邻元素子序列的最大和

代码思路

这段代码实现了一个特殊类型的线段树(Segment Tree),用于解决一类特定的动态规划问题,具体来说,是求解一系列更新操作后,一个特定子序列和的最大值问题。这里的子序列和受到一些特定的约束条件影响,这些条件通过线段树的节点(SegNode)中的四个值(v00v01v10v11)来体现。以下是对代码思路的详细解释:

数据结构定义

  1. SegNode 结构体
    • 包含四个 long long 类型的成员变量 v00v01v10v11,这些变量用于存储特定子序列和的最大值,具体含义取决于动态规划问题的约束条件。
  2. SegTree 结构体
    • 包含数组长度 n 和一个指向 SegNode 指针数组的指针 tree,这个指针数组用于存储线段树的节点。

函数实现

  1. segNodeCreate
    • 分配并初始化一个 SegNode 节点,将所有成员变量设置为 0。
  2. setSegNode
    • 根据给定的值 v 更新一个 SegNode 节点的状态,这里只将 v11 设置为 v 和 0 中的较大值,其他成员变量设置为特定值(0),这反映了特定问题的约束条件。
  3. bestSegNode
    • 返回 SegNode 节点中存储的最大子序列和,这里返回 v11
  4. segTreeCreate
    • 分配并初始化一个 SegTree,包括为线段树的每个节点分配 SegNode
  5. freeSegTree
    • 释放 SegTree 占用的内存。
  6. initSegTree 和 internalInit
    • 初始化线段树,根据输入数组 nums 设置每个节点的状态。
  7. updateSegTree 和 internalUpdate
    • 更新线段树中特定位置的值,并重新计算受影响的节点的状态。
  8. querySegTree
    • 查询线段树的根节点,获取当前线段树表示的最大子序列和。
  9. pushup
    • 根据左右子节点的状态更新当前节点的状态,这里的更新逻辑体现了动态规划问题的转移方程。

核心逻辑

  • 动态规划问题的转移方程
    • v00 表示从左子树到右子树不经过当前节点的最大子序列和。
    • v01 表示从左子树经过当前节点到右子树(但不经过右子树的右孩子)的最大子序列和。
    • v10 表示从右子树经过当前节点到左子树(但不经过左子树的左孩子)的最大子序列和。
    • v11 表示从左子树经过当前节点到右子树(可能经过右子树的右孩子)的最大子序列和。
    • 这些转移方程体现了在特定约束条件下,如何合并子问题的解来得到当前问题的解。
  • 应用场景
    • 这段代码可以用于解决一系列更新操作后,求取满足特定条件的最大子序列和问题。例如,在某些约束条件下,求取最长递增子序列和的问题。

示例函数 maximumSumSubsequence

  • 该函数展示了如何使用上述线段树来解决一个具体问题:给定一个数组 nums 和一系列更新操作(queries),每个操作将数组中的某个元素更新为新的值,求取所有更新操作后,满足特定条件(由线段树中的 v11 表示)的最大子序列和。

注意事项

  • 由于代码中使用了 fmax 函数和 long long 类型,这意味着它旨在处理可能很大的数值,避免溢出。
  • 代码中使用了模运算 MOD 来确保最终结果不会溢出,并且适用于某些需要取模的应用场景。
    typedef struct SegNode {
        long long v00, v01, v10, v11;
    } SegNode;
    
    SegNode* segNodeCreate() {
        SegNode* node = (SegNode*)malloc(sizeof(SegNode));
        node->v00 = node->v01 = node->v10 = node->v11 = 0;
        return node;
    }
    
    void setSegNode(SegNode* node, long long v) {
        node->v00 = node->v01 = node->v10 = 0;
        node->v11 = fmax(v, 0LL);
    }
    
    long long bestSegNode(SegNode* node) {
        return node->v11;
    }
    
    typedef struct SegTree {
        int n;
        SegNode** tree;
    } SegTree;
    
    SegTree* segTreeCreate(int n) {
        SegTree* tree = (SegTree*)malloc(sizeof(SegTree));
        tree->n = n;
        tree->tree = (SegNode**)malloc((n * 4 + 1) * sizeof(SegNode*));
        for (int i = 0; i < n * 4 + 1; i++) {
            tree->tree[i] = segNodeCreate();
        }
        return tree;
    }
    
    void freeSegTree(SegTree* tree) {
        for (int i = 0; i <= tree->n * 4; i++) {
            free(tree->tree[i]);
        }
        free(tree->tree);
        free(tree);
    }
    
    void initSegTree(SegTree* tree, int* nums) {
        internalInit(tree, nums, 1, 1, tree->n);
    }
    
    void updateSegTree(SegTree* tree, int x, int v) {
        internalUpdate(tree, 1, 1, tree->n, x + 1, v);
    }
    
    long long querySegTree(SegTree* tree) {
        return bestSegNode(tree->tree[1]);
    }
    
    void internalInit(SegTree* tree, int* nums, int x, int l, int r) {
        if (l == r) {
            setSegNode(tree->tree[x], nums[l - 1]);
            return;
        }
        int mid = (l + r) / 2;
        internalInit(tree, nums, x * 2, l, mid);
        internalInit(tree, nums, x * 2 + 1, mid + 1, r);
        pushup(tree, x);
    }
    
    void internalUpdate(SegTree* tree, int x, int l, int r, int pos, int v) {
        if (l > pos || r < pos) {
            return;
        }
        if (l == r) {
            setSegNode(tree->tree[x], v);
            return;
        }
        int mid = (l + r) / 2;
        internalUpdate(tree, x * 2, l, mid, pos, v);
        internalUpdate(tree, x * 2 + 1, mid + 1, r, pos, v);
        pushup(tree, x);
    }
    
    void pushup(SegTree* tree, int x) {
        int l = x * 2, r = x * 2 + 1;
        tree->tree[x]->v00 = fmax(tree->tree[l]->v00 + tree->tree[r]->v10, tree->tree[l]->v01 + tree->tree[r]->v00);
        tree->tree[x]->v01 = fmax(tree->tree[l]->v00 + tree->tree[r]->v11, tree->tree[l]->v01 + tree->tree[r]->v01);
        tree->tree[x]->v10 = fmax(tree->tree[l]->v10 + tree->tree[r]->v10, tree->tree[l]->v11 + tree->tree[r]->v00);
        tree->tree[x]->v11 = fmax(tree->tree[l]->v10 + tree->tree[r]->v11, tree->tree[l]->v11 + tree->tree[r]->v01);
    }
    
    #define MOD 1000000007
    
    int maximumSumSubsequence(int* nums, int numsSize, int** queries, int queriesSize, int* queriesColSize) {
        SegTree* tree = segTreeCreate(numsSize);
        initSegTree(tree, nums);
    
        long long ans = 0;
        for (int i = 0; i < queriesSize; i++) {
            updateSegTree(tree, queries[i][0], queries[i][1]);
            ans = (ans + querySegTree(tree)) % MOD;
        }
        freeSegTree(tree);
        return (int)ans;
    }
    

你可能感兴趣的:(算法,数据结构)