树状数组区间修改和区间求和

最一般树状数组能做到的操作是单点修改,区间求和,都是log(n)级别的。原理就是用树状数组维护a[i]的部分和。

想要做到修改区间,求单点值也很简单,用树状数组维护a[i]的差分数组d[i]的部分和既可。

那么,如何同时做到区间求和,区间修改呢?

有人可能会说了,如果是区间求和区间修改的话,直接写线段树不就好了吗?

但是,从代码长度来看(dalao请无视),显然使用树状数组在考场上出错率会小一些,而且比较爽QWQ

回归正题。我们知道,想要达到log(n)级别的区间修改需要修改d[i],那么在修改d[i]的情况下想要区间求和,我们就应该维护这个:

找出d[i]与a[i]的前缀和的关系,并用树状数组维护这个关系。

那么如何找关系呢?这里需要一点点数学证明:

我们设sum(i)=a[1]+a[2]+a[3]+······+a[i],

则可知

sum(i)=(d[1])+(d[1]+d[2])+(d[1]+d[2]+d[3])+······+(d[1]+d[2]+d[3]+······+d[i]),

所以

sum(i)=i*d[1]+(i-1)*d[2]+(i-2)*d[3]+······+1*d[i],

所以

sum(i)=∑(j从1到i)(i-j+1)d[j],

最后一步化简后,我们得到这样一个式子:

sum(i)=(i+1)∑(j从1到i)d[j]-∑(j从1到i)j*d[j]

即我们需要用树状数组分别维护d[i]的和和i*d[i]的和既可。

下面上代码:

 1#include <iostream> 2#include <cstdio> 3#include <cstdlib> 4#include <algorithm> 5using namespace std; 6 7long long n,m; 8long long c1[100010],c2[100010]; 910void update(long long x,long long k)11{12    long long i=x;13    while(x<=n)14    {15        c1[x]+=k;16        c2[x]+=i*k;17        x+=x&-x;18    }19    return;20}2122long long sum(long long x)23{24    long long ans=0;25    long long i=x;2627    while(x>0)28    {29        ans+=c1[x]*(i+1);30        ans-=c2[x];31        x-=x&-x;32    }33    return ans;34}3536int main()37{38    long long ord,x,y,k;39    long long a,b=0;4041    scanf("%lld%lld",&n,&m);42    for(long long i=1;i<=n;i++)43    {44        scanf("%lld",&a);45        update(i,a-b);46        b=a;47    }48    for(long long i=1;i<=m;i++)49    {50        scanf("%lld",&ord);51        if(ord-1)52        {53            scanf("%lld%lld",&x,&y);54            printf("%lld\n",sum(y)-sum(x-1));55        }56        else57        {58            scanf("%lld%lld%lld",&x,&y,&k);59            update(x,k);60            update(y+1,-k);61        }62    }63    return 0;64}

原文地址:https://www.cnblogs.com/CYHeimu/p/11058205.html

时间: 2024-11-10 05:36:17

树状数组区间修改和区间求和的相关文章

hdu4417 树状数组(求指定区间比指定数小的数的个数)

http://acm.hdu.edu.cn/showproblem.php?pid=4417 Problem Description Mario is world-famous plumber. His "burly" figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble again and Mario needs to save his lover.

Libre OJ 130、131、132 (树状数组 单点修改、区间查询 -&gt; 区间修改,单点查询 -&gt; 区间修改,区间查询)

#130. 树状数组 1 :单点修改,区间查询 题目链接:https://loj.ac/problem/130 题目描述 这是一道模板题. 给定数列 a[1], a[2], \dots, a[n]a[1],a[2],…,a[n],你需要依次进行 qq 个操作,操作有两类: 1 i x:给定 i,xi,x,将 a[i]a[i] 加上 xx: 2 l r:给定 l,rl,r,求 \sum_{i=l}^ra[i]∑i=lr?a[i] 的值(换言之,求 a[l]+a[l+1]+\dots+a[r]a[l

未解决的树状数组差分(改变区间,求单点值)

// luogu-judger-enable-o2 #include <bits/stdc++.h> #define inf 500001 #define lll long long int using namespace std; long c[inf],a,n,m,k,xx,nn; int lowbit(int x){ return x&(-x);//求X二进制下从右到左第一个1的所对应的十进制下的值 } void update(int x,int y){//update添加修改之

10:Challenge 3(树状数组直接修改)

总时间限制:  10000ms 单个测试点时间限制:  1000ms 内存限制:  262144kB 描述 给一个长为N的数列,有M次操作,每次操作是以下两种之一: (1)修改数列中的一个数 (2)求数列中某连续一段的和 输入 第一行两个正整数N和M.第二行N个整数表示这个数列.接下来M行,每行开头是一个字符,若该字符为'M',则表示一个修改操作,接下来两个整数x和y,表示把x位置的值修改为y:若该字符为'Q',则表示一个询问操作,接下来两个整数x和y,表示求[x,y]这段区间的和. 输出 对每

HDU4267 树状数组 不连续区间修改

A Simple Problem with Integers                                   Time Limit: 5000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description Let A1, A2, ... , AN be N elements. You need to deal with two kinds of operations

【算法系列学习】线段树vs树状数组 单点修改,区间查询 [kuangbin带你飞]专题七 线段树 A - 敌兵布阵

https://vjudge.net/contest/66989#problem/A 单点修改,区间查询 方法一:线段树 http://www.cnblogs.com/kuangbin/archive/2011/08/15/2139834.html 1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<cmath> 6 #

树状数组 模板 单点更新 区间求和

(来自luogu)原题目 lowbit(x)=2^k次幂,k为x末尾0的数量.大家可以模拟试试lowbit (-x)=(~x)+1,把x取反+1 void update(int x,int k)表示a[x]+=k(单点更新) int sum(int x)表示求1-x区间和 求x-y区间和只需要sum(y)-sum(x-1)即可 #include <iostream> #include <string> #include <cstring> #define lowbit(

树状数组变形:带区间修改的树状数组

原理很简单,利用差分知识做的,只能单点查询,在性能上优于线段树,但没有区间查询功能. 1 #include<bits/stdc++.h> 2 #define f(i,a,b) for(int i=a;i<=b;i++) 3 using namespace std; 4 5 const int N=5e5+5; 6 int n,q,opt,le,ri,pos,val; 7 int a[N]; 8 int tree[N]; 9 #define lowbit(x) (x&(-x)) 1

Turing Tree HDU - 3333 (树状数组,离线求区间元素种类数)

After inventing Turing Tree, 3xian always felt boring when solving problems about intervals, because Turing Tree could easily have the solution. As well, wily 3xian made lots of new problems about intervals. So, today, this sick thing happens again..

LA 2191 树状数组 稍修改

题意:给出n个数字,操作有修改(S)和输出区间和(M). #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <queue> #include <stack> #include <map> #include <