一维数状数组区间修改,查询

模板题CODEVS-1082

给你N个数,有两种操作:

1:给区间[a,b]的所有数增加X

2:询问区间[a,b]的数的和。

第一行一个正整数n,接下来n行n个整数,

再接下来一个正整数Q,每行表示操作的个数,

如果第一个数是1,后接3个正整数,

表示在区间[a,b]内每个数增加X,如果是2,

表示操作2询问区间[a,b]的和是多少。

一维树状数组可以考虑用差分来做,但是扩展不到二维。

所以我们令di=(ai~an)的增量

思路和差分一样,可以扩展到二维(现在还没懂)

#include<iostream>
#include<cstdio>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
#define lowbit(x) x&(-x)
int n,m,a[1000005],c1[1000005],c2[1000005];
void update(int v,int val)
{
    for(int pp=v;pp<=n;c1[pp]+=val,c2[pp]+=val*v,pp+=lowbit(pp));
}
int query(int l,int r)
{
    int ans=0;
    for(int pp=r;pp>0;ans+=(r+1)*c1[pp],ans-=c2[pp],pp-=lowbit(pp));
    l--;
    for(int pp=l;pp>0;ans-=(l+1)*c1[pp],ans+=c2[pp],pp-=lowbit(pp));
    return ans;
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    update(i,a[i]-a[i-1]);

    for(int i=1;i<=m;i++)
    {
        int p,l,r,val;
        scanf("%d %d %d",&p,&l,&r);
        if(p==1)
        {
            scanf("%d",&val);
            update(l,val);
            update(r+1,-val);
        }else
        {
            printf("%d\n",query(l,r));
        }
    }

    return 0;
}
时间: 2024-08-26 05:03:01

一维数状数组区间修改,查询的相关文章

【学习整理】树状数组 区间修改+查询

前言:对于区间修改和区间查询这样的简单问题,打一大堆线段树确实是不划算,所以学习了区间修改+区间修查询的树状数组. 我们定义 为原数列, ,显然  . 若想要将区间 的数全部 则只需要将 , 即可. 所以,我们维护一个数组 在将区间 的数全部 则还需同时将 , . 结论: 例题:CODEVS1082 线段树练习3 http://codevs.cn/problem/1082/ #include<iostream> #include<cstdio> #include<cstdli

HDU - 1556 Color the ball (一维树状数组 + 区间修改 + 单点求值)

HDU - 1556 Color the ball Time Limit: 3000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Submit Status Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色.但是N次以后lele已经忘记了第I个气

poj3468区间加减查找——树状数组区间修改查询

题目:http://poj.org/problem?id=3468 增加一个更改量数组,施以差值用法则区间修改变为单位置修改: 利用公式可通过树状数组维护两个数组:f与g而直接求出区间和. 代码如下: #include<iostream> #include<cstdio> using namespace std; long long n,q,a[100005]/*,b[100005],bg[100005]*/,l,r,ad; long long f[100005],g[100005

【bzoj3110】[Zjoi2013]K大数查询 整体二分+树状数组区间修改

题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. 输入 第一行N,M接下来M行,每行形如1 a b c或2 a b c 输出 输出每个询问的结果 样例输入 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 样例输出 1 2 1 题解 整体二分+树状数组区间修改 当年naive的树套树题解 前两天由于要

【bzoj4540】[Hnoi2016]序列 单调栈+离线+扫描线+树状数组区间修改

题目描述 给出一个序列,多次询问一个区间的所有子区间最小值之和. 输入 输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数.接下来一行,包含n个整数,以空格隔开,第i个整数为ai,即序列第i个元素的值.接下来q行,每行包含两个整数l和r,代表一次询问. 输出 对于每次询问,输出一行,代表询问的答案. 样例输入 5 5 5 2 4 1 3 1 5 1 3 2 4 3 5 2 5 样例输出 28 17 11 11 17 题解 单调栈+离线+扫描线+树状数组区间修改 首先把使用单调栈找出每个

【bzoj5173】[Jsoi2014]矩形并 扫描线+二维树状数组区间修改区间查询

题目描述 JYY有N个平面坐标系中的矩形.每一个矩形的底边都平行于X轴,侧边平行于Y轴.第i个矩形的左下角坐标为(Xi,Yi),底边长为Ai,侧边长为Bi.现在JYY打算从这N个矩形中,随机选出两个不同的矩形,并计算它们的并的大小.JYY想知道,交的大小的期望是多少.换句话说即求在所有可能的选择中,两个矩形交的面积的平均大小是多大. 输入 输入一行包含一个正整数N. 接下来N行,每行4个整数,分别为Xi,Yi,Ai,Bi 2 < =  N < =  2*10^5, 0 < =  Xi,

【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询

题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作,每次为一下三种之一: RELEASE x:对x执行一次感染: RECENTER x:把根节点改为x,并对原来的根节点执行一次感染: REQUEST x:询问x子树中所有节点感染代价的平均值. 输入 输入的第一行包含两个整数n和m,分别代表局域网中计算机的数量,以及操作和询问的总数.接下来n-1行,

树状数组 区间修改+区间查询

其实直到不久前都几乎不会用树状数组,请教了PPZ大佬之后终于懂了一点点. 然后小蒟蒻现在才知道了树状数组区间修改+区间查询的方法QAQ 传送门 Codevs 线段树练习3 //Twenty #include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<queu

【树状数组区间修改单点查询+分组】HDU 4267 A Simple Problem with Integers

http://acm.hdu.edu.cn/showproblem.php?pid=4267 [思路] 树状数组的区间修改:在区间[a, b]内更新+x就在a的位置+x. 然后在b+1的位置-x 树状数组的单点查询:求某点a的值就是求数组中1~a的和. (i-a)%k==0把区间分隔开了,不能直接套用树状数组的区间修改单点查询 这道题的K很小,所以可以枚举k,对于每个k,建立k个树状数组,所以一共建立55棵树 所以就可以多建几棵树..然后就可以转换为成段更新了~~ [AC] 1 #include