树状数组求区间和模板 区间可修改 参考题目:牛客小白月赛 I 区间
从前有个东西叫树状数组,它可以轻易实现一些简单的序列操作,比如单点修改,区间求和;区间修改,单点求值等.
但是我们经常需要更高级的操作,比如区间修改区间查询.这时候树状数组就不起作用了,只能选择写一个2000GB的线段树交上去然后被卡常—–或者另一个选择是写ZKW线段树,会好一些.
再但是…谁告诉你树状数组不能区间修改区间求和?告诉你,树状数组不仅能实现,而且代码依旧那么短小精悍.
今天我们就来研究研究,如何实现这个更划算的数据结构.
我们已经学会了树状数组的基本操作:单点修改区间查询,或区间修改单点查询(不会的话先去自学吧…这篇文章不适合你…).思考,区间修改单点求值是怎么做到的?只需要维护一个新数组c[i]=a[i]-a[i-1],也就是c[]是a[]的差分数组,修改区间[l,r]+v只需
add(l,v);add(r+1,-v) //从l加到了n,r以后的多加了,所以要再进行次r+1到n加-v的操作
即可.求某个值的时候,只需要把差分数组的前缀和求出来,就是要求的了.
领悟了这个操作以后我们发现,化区间为单点的思想精髓就在于差分二字.利用差分思想,区间修改解决了,接下来就是区间求和公式的推导过程:
sum(1,n)
=a[1]+a[2]+a[3]+…+a[n-1]+a[n]
=c[1]+(c[1]+c[2])+…+(c[1]+c[2]+…+c[n])
=n*(c[1]+c[2]+…+c[n])-(0*c[1]+1*c[2]+2*c[3]+…+(n-1)*c[n]).
发现什么了?
我们开第二个树状数组c2,令c2[i]=c[i]*(i-1),那么…
区间修改[l,r]+=v:
add(c[l],v),add(c[r+1],-v);
add(c2[l],(l-1)*v),add(c2[r+1],-r*v);
求前缀和sum(1,n):
sum(1,n)=n*query_c(n)-query_c2(n).
求区间和sum(l,r):
sum(l,r)=sum(r)-sum(l-1).
至此,树状数组已经轻松实现了区间修改区间求和!
例题:luogu 3372线段树模板 这题用线段树写500+ms,拿裸的树状数组311ms就切掉了,代码也养眼得多.至于zkw的效率如何我不太清楚.
顺便:其实一开始建树的时候没必要把原来数组的元素一个个扔进树里,直接维护一个前缀和,然后计算的时候加上这个前缀和就好了.省去了nlogn的建树操作,会快很多.此处为了增强代码可读性,没有加这一句.
参考博客:
https://ahackh.ac.cn/2017/06/25/%E8%89%AF%E5%BF%83%E8%AF%A6%E8%A7%A3%E6%A0%91%E7%8A%B6%E6%95%B0%E7%BB%84%E3%81%AE%E5%8C%BA%E9%97%B4%E4%BF%AE%E6%94%B9%E6%B1%82%E5%92%8C%E6%9C%89%E8%BF%99%E7%A7%8D%E6%93%8D%E4%BD%9C/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 102333
using namespace std;
typedef long long ll;
int n,m;
ll a[N],c1[N],c2[N];
inline int lowbit(int x){return x&(-x);}
void add(ll *r,int pos, ll v)
{for(;pos<=n;pos+=lowbit(pos))r[pos]+=v;
}
ll getsum(ll *r,int pos)
{ll re=0;for(;pos>0;pos-=lowbit(pos))re+=r[pos];return re;
}
ll sigma(int r)
{ll sum1=r*getsum(c1,r),sum2=getsum(c2,r);return sum1-sum2;
}
ll query(int x,int y)
{return sigma(y)-sigma(x-1);
}
int flag,x,y;ll k;
int main()
{cin>>n>>m;for(int i=1;i<=n;i++){scanf("%lld",&a[i]);add(c1,i,a[i]-a[i-1]);add(c2,i,(i-1)*(a[i]-a[i-1]));}for(int i=1;i<=m;i++){scanf("%d",&flag);if(flag==1){scanf("%d%d%lld",&x,&y,&k);add(c1,x,k);add(c1,y+1,-k);add(c2,x,(x-1)*k);add(c2,y+1,y*(-k));}else{scanf("%d%d",&x,&y);printf("%lld\n",query(x,y));}}return 0;
}
类似题目: 区间
链接:https://www.nowcoder.com/acm/contest/135/I
来源:牛客网
题目描述
Apojacsleam喜欢数组。
他现在有一个n个元素的数组a,而他要对a[L]-a[R]进行M次操作:
操作一:将a[L]-a[R]内的元素都加上P
操作二:将a[L]-a[R]内的元素都减去P
输入描述:
输入共M+3行: 第一行两个数,n,M,意义如“题目描述” 第二行n个数,描述数组。 第3-M+2行,共M行,每行四个数,q,L,R,P,若q为1则表示执行操作2,否则为执行操作1 第4行,两个正整数l,r
输出描述:
一个正整数,为a[l]-a[r]内的元素之和
输入
复制
10 5 1 2 3 4 5 6 7 8 9 10 1 1 5 5 1 2 3 6 0 2 5 5 0 2 5 8 1 4 9 6 2 7
输出
复制
23
说明
//树状数组(升级版)
#include <cstdio>
#define lowbit(x) (x&-x)
#define ll long long
#define maxn 1000010
using namespace std;
ll n, q, c1[maxn], c2[maxn], num[maxn];
void add(ll *r, ll pos, ll v)
{for(;pos<=n;pos+=lowbit(pos))r[pos]+=v;}
ll sigma(ll *r, ll pos)
{ll ans;for(ans=0;pos;pos-=lowbit(pos))ans+=r[pos];return ans;
}
int main()
{ll i, j, type, a, b, v, sum1, sum2;scanf("%lld",&n);scanf("%lld",&q);for(i=1;i<=n;i++){scanf("%lld",num+i);add(c1,i,num[i]-num[i-1]);add(c2,i,(i-1)*(num[i]-num[i-1]));}while(q--){scanf("%lld",&type);if(type!=1){scanf("%lld%lld%lld",&a,&b,&v);add(c1,a,v);add(c1,b+1,-v);add(c2,a,v*(a-1));add(c2,b+1,-v*b);} else {scanf("%lld%lld%lld",&a,&b,&v);add(c1,a,-v);add(c1,b+1,v);add(c2,a,-v*(a-1));add(c2,b+1,v*b);}}scanf("%lld%lld",&a,&b);sum1=(a-1)*sigma(c1,a-1)-sigma(c2,a-1);sum2=b*sigma(c1,b)-sigma(c2,b);printf("%lld\n",sum2-sum1);return 0;
}
转载于:https://www.cnblogs.com/l609929321/p/9366792.html
树状数组求区间和模板 区间可修改 参考题目:牛客小白月赛 I 区间相关推荐
- poj 3486 A Simple Problem with Integers(树状数组第三种模板改段求段)
1 /* 2 树状数组第三种模板(改段求段)不解释! 不明白的点这里:here! 3 */ 4 #include<iostream> 5 #include<cstring> 6 ...
- 牛客练习赛33 D tokitsukaze and Inverse Number (树状数组求逆序对,结论)
链接:https://ac.nowcoder.com/acm/contest/308/D 来源:牛客网 tokitsukaze and Inverse Number 时间限制:C/C++ 1秒,其他语 ...
- hdu1754(树状数组求最值问题)
I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- poj 2299 Ultra-QuickSort(树状数组求逆序数+离散化)
题目链接:http://poj.org/problem?id=2299 Description In this problem, you have to analyze a particular so ...
- nyoj 1261 音痴又音痴的LT(离散化+树状数组求K小数)
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=1261 解题思路:比较水的题,用离散化+树状数组求K小数即可,先用一次离线处理. #inc ...
- 离散化+树状数组求逆序数
题目:http://poj.org/problem?id=2299 离散化是一种常用的技巧,有时数据范围太大,可以用来放缩到我们能处理的范围 因为其中需排序的数的范围0--- 999999999:显然 ...
- loj #535. 「LibreOJ Round #6」花火 树状数组求逆序对+主席树二维数点+整体二分...
$ \color{#0066ff}{ 题目描述 }$ 「Hanabi, hanabi--」 一听说祭典上没有烟火,Karen 一脸沮丧. 「有的哦-- 虽然比不上大型烟花就是了.」 还好 Shinob ...
- 牛客小白月赛13-H(单调栈+树状数组)
题目链接:https://ac.nowcoder.com/acm/contest/549/H 题意:给一个柱状图,包括每个矩阵的宽度和高度,求能组成的最大矩阵的面积. 思路:显然最大矩阵的高一定为n个 ...
- 牛客小白月赛5 I.区间 (interval)
牛客小白月赛5 I.区间 (interval) 题目链接 题目描述 Apojacsleam喜欢数组.他现在有一个n个元素的数组a,而他要对a[L]-a[R]进行M次操作:操作一:将a[L]-a[R]内 ...
最新文章
- python字典的setdefault方法和get方法
- boost::system模块实现初始化顺序的测试程序
- Homebrew替换源
- openshift4离线部署_OpenShift 4.2 离线安装补充记录
- zoj3777(状态压缩)
- Libevent源码分析
- linux c代码调试工具,在 Linux 中调试 C 程序的福音——gdb
- 编程程序 runtime error
- Tourists——圆方树
- OSChina 周三乱弹 —— 东京不热,北海道有点热
- 求 Fibonacci 数列的前 20 项
- 【原创】RPA在BPO领域的场景分享-中科云创CEO每日分享
- no default constructor found either
- [Luogu P3613] 睡觉困难综合征
- 2020 ICM Weekend 1 Problem E: Drowning in Plastic
- 《工程伦理》网课第十章课后习题答案
- torch.contiguous()函数用法
- 生物信息学常用名词解释
- 《Java语言程序设计与数据结构(基础篇)》第11版第四章复习题答案
- 程序猿解决BUG之总结
热门文章
- python 爬虫源代码-python 爬虫-1:下载网页源代码
- python编程培训-马哥教育官网-专业Linux培训班,Python培训机构
- python 单词发音-在python中的单词上拆分语音音频文件
- python爬虫工程师-Python爬虫工程师
- python程序员在公司都是做什么的-程序员是做什么的?工资待遇怎么样?
- LeetCode Single Number II(位操作)
- UVa11402 Ahoy, Pirates!
- 解读分库分表中间件Sharding-JDBC
- Problem C: 指针:自定义函数length,调用它计算字符串的长度
- 9.3 域名解析与网页爬虫