吊打线段树的超级树状数组
你是否讨厌线段树那冗长的代码?你是否还在因为线段树的难调试而满头♂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
吊打线段树的超级树状数组相关推荐
- 树套树 ----- 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],我们要减去[ ...
- 树套树 ---- 树状数组套权值线段树模板题 P2617 Dynamic Rankings 动态第K大
题目链接 题目大意: 给你一个数组aaa,aaa有两个操作 询问aaa中[l,r][l,r][l,r]区间里面第kkk小的数是哪个? 修改axa_xax为yyy 解题思路: 首先我们知道权值线段树是 ...
- poj 2352 Stars 线段树(先建后查/边建边查)/树状数组三种方法思路详解,带你深入了解线段树难度⭐⭐⭐★
poj 2352 Stars 目录 poj 2352 Stars 1.树状数组 2.线段树,先建树后查找 3.线段树,边建树边查找 Description Astronomers often exam ...
- 8.8线段树和树状数组
题目链接 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28619#overview 密码 acmore 还是感觉不怎么会线段树,还是 ...
- 线段树/树状数组问题 | 问题集合
写在前面 线段树代码实在冗长,于是乎能用树状数组直接搞的就懒得打线段树了(:溜 1.P2620[QZYZ] 校门外的树 描述 Description 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有 ...
- 花神游历各国 题解(小清新线段树/树状数组+并查集)
题面 众所周知,这是一道小清新线段树 然而可以用树状数组水过去且跑得飞快 看到区间开方第一反应肯定是线段树懒标记区间修改之类的,但是这个东西似乎确凿不可维护 所以考虑暴力循环单点修改->T飞 于 ...
- LeetCode Range Sum Query - Mutable(树状数组、线段树)
问题:给出一个整数数组,求出数组从索引i到j范围内元素的总和.update(i,val)将下标i的数值更新为val 思路:第一种方式是直接根据定义,计算总和时直接计算从i到j的和 第二种方式是使用树状 ...
- hdu 4417(线段树OR树状数组)
题意:输入一个长度为n的序列,然后m个询问,询问区间[a,b]中比h小的数的个数. 思路:树状数组或线段树离线处理. 树状数组1 View Code 1 #include<cstdio> ...
- 【bzoj4881】[Lydsy2017年5月月赛]线段游戏 树状数组+STL-set
题目描述 quailty和tangjz正在玩一个关于线段的游戏.在平面上有n条线段,编号依次为1到n.其中第i条线段的两端点坐标分别为(0,i)和(1,p_i),其中p_1,p_2,...,p_n构成 ...
最新文章
- 计算机基础在小学的教学论文,小学基础教育论文范文
- WPF动画的属性被劫持
- php 多维数组 array sort 排序 :array_multisort
- OpenSceneGraph学习笔记
- 使用 Edit + MASM 5.0 编译器 + Linker 连接器
- java ee cdi_Java EE CDI限定词:快速浏览
- 手把手带你做LiteOS的树莓派移植
- UI设计灵感|注册登录界面设计灵感
- amd锐龙笔记本cpu怎么样_AMD的锐龙处理器怎么样?AMD的市占率高吗?
- Python+matplotlib绘制三维图形5个精选案例
- css3:border-radius圆角边框详解 (变圆 图片)
- open cv+C++错误及经验总结(十二)
- linux虚拟机怎么恢复出厂设置_Vmware安装linux后一些初始化配置
- Smart3D软件基本操作步骤
- 分享一种快速制作证件照的方法,只要你有自拍照就完全ok啦
- 车联网 北斗GPS 部标平台 JT/T808
- 贝叶斯网络和马尔科夫的冷知识
- 如何设计一份令人舒服的PPT,每次看都有新的idea
- win10系统进不了服务器失败,快速解决Win10安装失败重启进不了系统的方法
- pmp项目管理的优先级解决方法