• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • YouClaw
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

RomanLin

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

【单点修改,区间查询】洛谷 P3374 【模板】树状数组 1

题目

https://www.luogu.com.cn/problem/P3374

参考代码

#include<bits/stdc++.h>
typedef long long ll;

template<typename E, typename F, typename F_INVERSE>
class FenwickTree {// 树状数组
private:
    std::vector<E> raw;// 维护原数据
    std::vector<E> tree;// 树状数组
    int arr_size;// 元素个数
    F func;// 代表元素运算规则,例如加法
    F_INVERSE func_inverse;// 代表 func 的逆运算规则,例如加法的逆运算规则就是减法
    E defaultValue;// 树状数组初始化的元素值
    bool prefixToSuffix;// 用前缀树状数组维护后缀树状数组

    /* 计算出 x 二进制形式下最低位的 1 */
    inline int lowbit(int x) {
        return x & -x;
    }
    /* 有可能使用前缀树状数组维护后缀树状数组,因此需要计算出真实下标位置 */
    inline int calculateRealIndex(int x) {
        return prefixToSuffix ? arr_size - x + 1 : x;
    }

public:
    /**
     * 容器内的元素下标从 0 开始存放,但是树状数组的使用是从下标 1 开始使用
     * @tparam Container 容器类型
     * @param arr 存放元素的容器
     * @param arr_size 容器大小
     * @param func 容器中元素的运算规则
     * @param func_inverse 容器中元素的逆运算规则
     * @param defaultValue 容器中元素的默认值
     */
    template<typename Container>
    FenwickTree(Container&& arr, int arr_size, F func, F_INVERSE func_inverse, E defaultValue, bool prefixToSuffix = false)
            : arr_size(arr_size), func(func), func_inverse(func_inverse), defaultValue(defaultValue), prefixToSuffix(prefixToSuffix) {
        raw.resize(arr_size + 1);
        tree.assign(arr_size + 1, defaultValue);
        for (int i = 0; i < arr_size; ++ i) {
            raw[i + 1] = arr[i];
            pointUpdate(i + 1, arr[i]);
        }
    }
    /* 没有初始容器数据的构造器 */
    FenwickTree(int arr_size, F func, F_INVERSE func_inverse, E defaultValue, bool prefixToSuffix = false)
            : arr_size(arr_size), func(func), func_inverse(func_inverse), defaultValue(defaultValue), prefixToSuffix(prefixToSuffix) {
        raw.assign(arr_size + 1, defaultValue);
        tree.assign(arr_size + 1, defaultValue);
    }

    /* 单点赋值:将下标 index(从 1 开始)的值改为 newValue */
    void pointAssign(int index, E newValue) {
        // 原本的值为 value 要变为 newValue,相当于 func(value, func_inverse(newValue, value))
        index = calculateRealIndex(index);
        E delta = func_inverse(newValue, raw[index]);
        raw[index] = newValue;
        pointUpdate(index, delta);
    }
    /* 单点修改:将下标 index(从 1 开始)的值与 value 进行 func 运算 */
    void pointUpdate(int index, E value) {
        index = calculateRealIndex(index);
        for (int i = index; i <= arr_size; i += lowbit(i)) {
            tree[i] = func(tree[i], value);
        }
    }
    /* 前缀查询:查询下标 index(从 1 开始)的值 */
    E prefixQuery(int index) {
        index = calculateRealIndex(index);
        E res = defaultValue;
        for (int i = index; i > 0; i -= lowbit(i)) {
            res = func(res, tree[i]);
        }
        return res;
    }
    /* 区间查询:查询区间 [leftIndex, rightIndex] 进行 func 运算的结果 */
    E rangeQuery(int leftIndex, int rightIndex) {
        E difference = func_inverse(prefixQuery(rightIndex), prefixQuery(leftIndex - 1));// 使用 func 的逆运算规则 func_inverse 做差分
        return difference;// 差分的值即为区间 [leftIndex, rightIndex] 进行 func 运算的结果
    }
};

class FenwickTreeFactory {
public:
    /* 前缀模式的加法树状数组:修改向后,查询向前 */
    template<typename Container>
    static auto add(Container&& arr, int arrSize, bool prefixToSuffix = false) {
        using T = std::remove_reference_t<decltype(arr[0])>;
        auto add_func = [](T a, T b) { return a + b; };
        auto sub_func = [](T a, T b) { return a - b; };
        return FenwickTree<T, decltype(add_func), decltype(sub_func)>(
                std::forward<Container>(arr), arrSize, add_func, sub_func, T(0), prefixToSuffix);
    }

    /* 后缀模式的加法树状数组:修改向前,查询向后 */
    template<typename Container>
    static auto addSuffix(Container&& arr, int arrSize) {
        return add(arr, arrSize, true);
    }

    // 乘法树状数组
    template<typename Container>
    static auto mul(Container&& arr, int arrSize) {
        using T = std::decay_t<decltype(arr[0])>;
        return FenwickTree<T,
                decltype([](T a, T b) { return a * b; }),
                decltype([](T a, T b) { return a / b; })
        >(std::forward<Container>(arr), arrSize,
          [](T a, T b) { return a * b; },
          [](T a, T b) { return a / b; },
          T(1));
    }

    // 异或树状数组
    template<typename Container>
    static auto xors(Container&& arr, int arrSize) {
        using T = std::decay_t<decltype(arr[0])>;
        auto op = [](T a, T b) { return a ^ b; };
        return FenwickTree<T, decltype(op), decltype(op)>(
                std::forward<Container>(arr), arrSize, op, op, T(0));
    }

    // 模加法树状数组
    template<typename Container>
    static auto modAdd(Container&& arr, int arrSize,
                       std::decay_t<decltype(arr[0])> mod) {
        using T = std::decay_t<decltype(arr[0])>;
        auto add = [mod](T a, T b) { return (a + b) % mod; };
        auto sub = [mod](T a, T b) { return (a - b + mod) % mod; };
        return FenwickTree<T, decltype(add), decltype(sub)>(
                std::forward<Container>(arr), arrSize, add, sub, T(0));
    }

    // 通用自定义工厂
    template<typename Container, typename Func, typename InvFunc>
    static auto custom(Container&& arr, int arrSize,
                       Func func, InvFunc invFunc,
                       std::decay_t<decltype(arr[0])> defaultVal) {
        using T = std::decay_t<decltype(arr[0])>;
        return FenwickTree<T, Func, InvFunc>(
                std::forward<Container>(arr), arrSize, func, invFunc, defaultVal);
    }
};

constexpr int N = 5e5 + 7;
int a[N];

int main() {
    std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout.tie(nullptr);
#ifdef ACM_LOCAL
    freopen("testCase.in", "r", stdin);
    freopen("testCase.out", "w", stdout);
#endif
    int n, m, op, x, y;
    std::cin >> n >> m;
    for (int i = 0; i < n; ++i) std::cin >> a[i];
    auto tr = FenwickTreeFactory::add(a, n);

    while (m --) {
        std::cin >> op >> x >> y;
        if (op == 1) {
            tr.pointUpdate(x, y);
        } else {
            std::cout << tr.rangeQuery(x, y) << '\n';
        }
    }

    return 0;
}

posted on 2026-04-28 23:55  RomanLin  阅读(2)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3