你是否讨厌线段树那冗长的代码?你是否还在因为线段树的难调试而满头♂dark汗?那么,请不要错过!超级树状数组特价!只要998,只要998!

##¥……#……¥%……&%¥……ER#%$#$#^T%$^$%

超级树状数组,其实是一种能够支持区间修改和区间查询的树状数组,和线段树相比,它的常数极小,不需要太多空间,代码量也少了很多(简直吊打线段树)

1.树状数组

既然是超级树状数组,那么就需要一个树状数组作为基础了。但是在真正实现时,只用到了lowbit()函数(所以说lowbit是树状数组的核心啊)

2.准备工作

首先,我们需要一个差分数组。

设a[]数组为原数组,那么tree[](差分数组)定义为tree[i]=a[i]-a[i-1]

猴子也能一眼看出的性质:a[i]=tree[1]+tree[2]+tree[3]+...+tree[i]

3.区间查询

(为什么先说查询呢。。)

(1)查询区间1.....l的和

sum[l]=a[1]+a[2]+...+a[l]

其中a[i]=tree[1]+...+tree[i]

那么我们可以很那啥的得到这个式子

t1+t1+t2+t1+t2+t3+....+t1+t2+t3+....+tl(这啥玩意啊)

如果你用数学角度去看的话,它是下面这个样子

t1*l+t2*(l-1)+t3*(l-2)+....+tl*1

如果你旁边坐着一位数竞大佬,ta会立刻看成这个样子

l*(t1+t2+....+tl)-(t1*0+t2*1+...+tl*(l-1))

然后我们惊奇的发现,这两个部分都是可以维护的

所以我们就可以在输入时处理出一个差分数组和一个tree1[i]=tree[i]*(i-1)

然后就可以查询了

(2)查询l.....r的和

类比前缀和处理

(3)代码

long long getsum(long long *arr,long long pos){long long sum=0;while(pos) sum+=arr[pos],pos-=lowbit(pos);return sum;
}
long long query(long long x,long long y){return y*getsum(d1,y)-(x-1)*getsum(d1,x-1)-(getsum(d2,y)-getsum(d2,x-1));
}

4.区间修改

类比树状数组的区间修改

void add(long long *arr,long long pos,long long x){while(pos<=n) arr[pos]+=x,pos+=lowbit(pos);
}

但是,由于tree和tree1的存在,修改需要改一下

void change(long long l,long long r,long long x){add(d1,l,x);add(d1,r+1,-x);add(d2,l,x*(l-1));add(d2,r+1,-x*r);
}

若是将区间l-r加上x,就可以tree[l]+x,tree[r]-x,这样保证在计算a[i]时能让l-r内的数+x而其他不+x

放代码

#include<cstdio>
#include<algorithm>
//long long tree[100001];
long long n,m;
long long d1[100001];
long long d2[100001];
inline long long lowbit(long long x)
{return x&-x;
}
/*void add(long long x,long long k)//μ¥μ?DT??
{while(x<=n){tree[x]+=k;x+=lowbit(x);}
}
long long sum(long long pos)
{//????2é?ˉ long long sum=0;while(pos){sum+=tree[pos];pos-=lowbit(pos);return sum;}
}
void add_ex(long long pos,long long x)
{//????DT?? while(pos<=n){detla[pos]+=x;pos+=lowbit(pos);}
}
void sum_ex(long long l,long long r,long long x)
{add_ex(l,x);add(r+1,-x);
}
long long sum_ex(long long pos)//μ¥μ?2é?ˉ
{long long sum=0;while(pos){sum+=detla[pos];pos-=lowbit(pos);}return sum;
}*/
//ò???ê?????DT??+????2é?ˉ
void add(long long *arr,long long pos,long long x){while(pos<=n) arr[pos]+=x,pos+=lowbit(pos);
}
void change(long long l,long long r,long long x){add(d1,l,x);add(d1,r+1,-x);add(d2,l,x*(l-1));add(d2,r+1,-x*r);
}
long long getsum(long long *arr,long long pos){long long sum=0;while(pos) sum+=arr[pos],pos-=lowbit(pos);return sum;
}
long long query(long long x,long long y){return y*getsum(d1,y)-(x-1)*getsum(d1,x-1)-(getsum(d2,y)-getsum(d2,x-1));
}//ò???ê?×??μ
/*
void build(long long n){for(long long i=1;i<=n;i++){tree[i]=a[i];long long t=lowbit(i);for(long long j=1;j<t;j*=2)tree[i]=std::max(tree[i],tree[i-j]);}
}
void add(long long pos,long long x){a[pos]=x;while(pos<=n){tree[pos]=a[pos];long long t=lowbit(i);for(long long j=1;j<t;j++){tree[i]=std::max(tree[i],tree[i-j]);}pos+=lowbit(pos);}
}
long long query(long long l,long long r){long long ans=a[r];while(1){ans=std::max(ans,tree[r]);if(r==l)break;r--;while(r-l>=lowbit(r))ans=std::max(ans,tree[r]),r-=lowbit(r);}return ans;
}
*/
int main()//ê÷×′êy×é′ó?£°?
{scanf("%lld%lld",&n,&m);long long a,b=0;for(long long i=1;i<=n;i++){scanf("%lld",&a);b=a-b;add(d1,i,b);add(d2,i,(i-1)*b);b=a;}while(m--){long long op;scanf("%lld",&op);if(op==1){//???μ long long x,y,z;scanf("%lld%lld%lld",&x,&y,&z);change(x,y,z);}else{long long x,y;//2é?ˉ scanf("%lld%lld",&x,&y);printf("%lld\n",query(x,y));}}
}

5.吊打线段树

现在让我们统计一下超级树状数组的核心代码长度

17行。。。。~~线段树你可以去死了~~

让我们看一下超级树状数组和线段树在跑模板时的时间与空间

ok线段树你真的可以当场去世了~

转载于:https://www.cnblogs.com/fxjrnh/p/9466423.html

吊打线段树的超级树状数组相关推荐

  1. 树套树 ----- P1975 [国家集训队]排队(树状数组套权值线段树求动态逆序对)

    解题思路: 首先我们知道交换两个数a[l]和a[r]a[l]和a[r]a[l]和a[r]影响到的区间是[l+1,r−1][l+1,r-1][l+1,r−1] 对于a[l]a[l]a[l],我们要减去[ ...

  2. 树套树 ---- 树状数组套权值线段树模板题 P2617 Dynamic Rankings 动态第K大

    题目链接 题目大意: 给你一个数组aaa,aaa有两个操作 询问aaa中[l,r][l,r][l,r]区间里面第kkk小的数是哪个? 修改axa_xax​为yyy 解题思路: 首先我们知道权值线段树是 ...

  3. poj 2352 Stars 线段树(先建后查/边建边查)/树状数组三种方法思路详解,带你深入了解线段树难度⭐⭐⭐★

    poj 2352 Stars 目录 poj 2352 Stars 1.树状数组 2.线段树,先建树后查找 3.线段树,边建树边查找 Description Astronomers often exam ...

  4. 8.8线段树和树状数组

    题目链接   http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28619#overview 密码 acmore 还是感觉不怎么会线段树,还是 ...

  5. 线段树/树状数组问题 | 问题集合

    写在前面 线段树代码实在冗长,于是乎能用树状数组直接搞的就懒得打线段树了(:溜 1.P2620[QZYZ] 校门外的树 描述 Description 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有 ...

  6. 花神游历各国 题解(小清新线段树/树状数组+并查集)

    题面 众所周知,这是一道小清新线段树 然而可以用树状数组水过去且跑得飞快 看到区间开方第一反应肯定是线段树懒标记区间修改之类的,但是这个东西似乎确凿不可维护 所以考虑暴力循环单点修改->T飞 于 ...

  7. LeetCode Range Sum Query - Mutable(树状数组、线段树)

    问题:给出一个整数数组,求出数组从索引i到j范围内元素的总和.update(i,val)将下标i的数值更新为val 思路:第一种方式是直接根据定义,计算总和时直接计算从i到j的和 第二种方式是使用树状 ...

  8. hdu 4417(线段树OR树状数组)

    题意:输入一个长度为n的序列,然后m个询问,询问区间[a,b]中比h小的数的个数. 思路:树状数组或线段树离线处理. 树状数组1 View Code 1 #include<cstdio> ...

  9. 【bzoj4881】[Lydsy2017年5月月赛]线段游戏 树状数组+STL-set

    题目描述 quailty和tangjz正在玩一个关于线段的游戏.在平面上有n条线段,编号依次为1到n.其中第i条线段的两端点坐标分别为(0,i)和(1,p_i),其中p_1,p_2,...,p_n构成 ...

最新文章

  1. 计算机基础在小学的教学论文,小学基础教育论文范文
  2. WPF动画的属性被劫持
  3. php 多维数组 array sort 排序 :array_multisort
  4. OpenSceneGraph学习笔记
  5. 使用 Edit + MASM 5.0 编译器 + Linker 连接器
  6. java ee cdi_Java EE CDI限定词:快速浏览
  7. 手把手带你做LiteOS的树莓派移植
  8. UI设计灵感|注册登录界面设计灵感
  9. amd锐龙笔记本cpu怎么样_AMD的锐龙处理器怎么样?AMD的市占率高吗?
  10. Python+matplotlib绘制三维图形5个精选案例
  11. css3:border-radius圆角边框详解 (变圆 图片)
  12. open cv+C++错误及经验总结(十二)
  13. linux虚拟机怎么恢复出厂设置_Vmware安装linux后一些初始化配置
  14. Smart3D软件基本操作步骤
  15. 分享一种快速制作证件照的方法,只要你有自拍照就完全ok啦
  16. 车联网 北斗GPS 部标平台 JT/T808
  17. 贝叶斯网络和马尔科夫的冷知识
  18. 如何设计一份令人舒服的PPT,每次看都有新的idea
  19. win10系统进不了服务器失败,快速解决Win10安装失败重启进不了系统的方法
  20. pmp项目管理的优先级解决方法

热门文章

  1. DLog-M什么意思
  2. 有没有和我一样从来不和亲戚联系的人?
  3. 负债人有尊严吗?我觉得真的没有
  4. 现在三十来岁的人存款大概多少?
  5. 组织体互联网是个啥?
  6. 搭建属于自己的私有链,部署简单的智能合约
  7. bluez 设置绑定pin码_「RT-Thread笔记」IO设备模型及PIN设备
  8. oracle执行外部sql_增强的PolyBase SQL 2019-Oracle DB的外部表
  9. dbcc收缩数据库_使用DBCC SHRINKFILE收缩数据库
  10. 树和二叉树2——输出广义表形式(带括号)二叉树