资瓷区间修改+区间求和的树状数组(一维/二维)

一维:令 \(v_i\) 为差分数组,那么 \([0, k]\) 的前缀和就是 \(\sum{v_i(k+1-i)} = (k+1) \cdot \sum{v_i} + \sum{v_i \cdot (-i)}\),树状数组维护一下 \(v_i\) 和 \(v_i \cdot i\) 即可。

template <typename I>
struct Fenwick {
    struct Node {
        I v0, v1;

        void add(I d0, I d1) {
            v0 += d0;
            v1 += d1;
        }

        void operator += (const Node &rhs) {
            v0 += rhs.v0;
            v1 += rhs.v1;
        }
    };

    Fenwick(int n) : n(n), tree(n) {}

    void orz(int k, I d0, I d1) {
        for (; k < n; k |= k + 1) {
            tree[k].add(d0, d1);
        }
    }

    void add(int l, int r, I d) { // [l, r)
        orz(l, d, -l * d);
        orz(r, -d, r * d);
    }

    I sum(int k) { // [0, k]
        Node res = {};
        for (int i = k; i >= 0; i = (i & (i + 1)) - 1) {
            res += tree[i];
        }
        return (k + 1) * res.v0 + res.v1;
    }

    I sum(int l, int r) { // [l, r)
        return sum(r - 1) - sum(l - 1);
    }

    int n;
    vector<Node> tree;
};

二维:和一维的推导类似,维护一下 \(v(i,j)\),\(v(i,j) \cdot i\),\(v(i,j) \cdot j\) 和 \(v(i,j) \cdot ij\)。

struct Fenwick {
    struct Node {
        int v, vi, vj, vij;

        void operator += (const Node &rhs) {
            v += rhs.v;
            vi += rhs.vi;
            vj += rhs.vj;
            vij += rhs.vij;
        }

        void apply(int d, int di, int dj, int dij) {
            v += d;
            vi += di;
            vj += dj;
            vij += dij;
        }
    };

    Fenwick(int n, int m) : n(n), m(m), tree(n, vector<Node>(m)) {}

    void add(int x, int y, int d) {
        int di = -x * d;
        int dj = -y * d;
        int dij = x * y * d;
        for (int i = x; i < n; i |= i + 1) {
            for (int j = y; j < m; j |= j + 1) {
                tree[i][j].apply(d, di, dj, dij);
            }
        }
    }

    int sum(int x, int y) {
        Node res = {};
        for (int i = x; i >= 0; i = (i & (i + 1)) - 1) {
            for (int j = y; j >= 0; j = (j & (j + 1)) - 1) {
                res += tree[i][j];
            }
        }
        return (x + 1) * (y + 1) * res.v + (y + 1) * res.vi + (x + 1) * res.vj + res.vij;
    }

    int n, m;
    vector< vector<Node> > tree;
};

原文地址:https://www.cnblogs.com/arg-53/p/9503281.html

时间: 2024-08-26 12:20:03

资瓷区间修改+区间求和的树状数组(一维/二维)的相关文章

【树状数组】树状数组一维二维模板

以下模板都是点更新,区间查询,如果是区间更新点查询,只需将利用lowbit的循环方向倒过来 一维: inline int lowbit(int x) { return x & -x; } void add(int x, int val) { for(int i = x; i <= n; i += lowbit(i)) C[i] += val; } int sum(int x) { int ret = 0; for(int i = x; i > 0; i -= lowbit(i)) re

poj 1195 二维树状数组 及二维树状数组模板

http://poj.org/problem?id=1195 求矩阵和的时候,下标弄错WA了一次... 求矩形(x1,y1) (x2,y2)的sum |sum=sum(x2,y2)-sum(x1-1,y2)-sum(x2,y1-1)+sum(x1-1,y1-1) 二维树状数组讲解:http://blog.csdn.net/u011026968/article/details/38532117 二维树状数组模板: /*========================================

[BZOJ4785][ZJOI2017]树状数组(概率+二维线段树)

4785: [Zjoi2017]树状数组 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 297  Solved: 195[Submit][Status][Discuss] Description 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道 基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进行 m 次操作,操作有两种: 1 x,表示将 Ax 变成 (Ax + 1)

poj2481树状数组解二维偏序

按区间r降序排列,r相同按照l升序排列,两个区间相同时特判一下即可 /* 给定n个闭区间[l,r],如果对区间[li,ri],[lj,rj]来说, 有区间j严格包含(两个边界不能同时重合)在区间i内,那么区间i大于区间j 问区间有多少个区间大于区间i 读入所有的区间,按r降序,l升序 然后按顺序访问每个区间, */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm>

poj 2155- Matrix (树状数组,二维,更新区间,查询单点)

Matrix Time Limit:3000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j]

HDU 2642(树状数组模板二维)

Stars Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/65536 K (Java/Others) Total Submission(s): 1350    Accepted Submission(s): 554 Problem Description Yifenfei is a romantic guy and he likes to count the stars in the sky. To make the

树状数组_二维

class TreeArraryTwo{ public : const static int cmaxn = 1e3+200; int date[cmaxn][cmaxn]; int xsz, ysz; void init(int size_x, int size_y) { xsz = size_x; ysz = size_y; memset(date, 0, sizeof(date)); } inline int lowbit(int idx) { return idx & -idx; } v

免费的馅饼 HYSBZ - 2131 (树状数组维护二维偏序)

题目链接:https://cn.vjudge.net/problem/HYSBZ-2131 题目大意:中文题目 具体思路:对于任意的两个位置,posA和posB,我们可以如下推导. |posA-posB|<=2*(tA-tB) 2*tB-2*tA<=posA-posB<=2*tB-2*tA. 2*tA+posA>=2*tB+posB  || 2*tA -pos A > = 2*tB-posB.(注意这个地方,只要有一个满足就可以了) 然后我们对2*tA+posA进行排序,每一

树状数组(二叉索引树 BIT Fenwick树) *【一维基础模板】(查询区间和+修改更新)

刘汝佳:<训练指南>Page(194) #include <stdio.h> #include <string.h> #include <stdlib.h> #include <algorithm> using namespace std; //一维树状数组基础模板 int lowbit(int x) { return x&(-x); } int c[1001]; int sum(int x) //计算从1到x的数组元素的和 { int