树状数组 1/30
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树状数组 1/30相关的知识,希望对你有一定的参考价值。
树状数组分为三大类:
1.单点修改+区间求和
2.区间修改+单点求和(运用工具差分数组)
3.区间修改+区间求和(维护两个数组的前缀和)
典型的差分思想:
https://www.luogu.com.cn/problem/P3655
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
ll N,S,Q,T,c[maxn],ls;
ll ans;
inline ll cc(ll x)
if(x>0)
return -S*x;
return -T*x;
int main()
scanf("%lld%lld%lld%lld",&N,&Q,&S,&T);
for(register ll i=0;i<=N;i++)
ll x;scanf("%lld",&x);
c[i]=x-ls;
ls=x;
ans+=cc(c[i]);
for(register ll i=1;i<=Q;i++)
ll x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
ans-=cc(c[x]);
c[x]+=z;
ans+=cc(c[x]);
if(y!=N)
ans-=cc(c[y+1]);
c[y+1]-=z;
ans+=cc(c[y+1]);
printf("%lld\\n",ans);
return 0;
一.单点修改+区间求和
https://www.luogu.com.cn/problem/P3374
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+5;
ll c[maxn],d[maxn],n,m;
void add(ll i,ll val)
while(i<=n)
c[i]+=val;
i+=i&(-i);
ll ask(ll i)
ll ret=0;
while(i>0)
ret+=c[i];
i-=i&(-i);
return ret;
int main()
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n;i++)
int h;
scanf("%lld",&h);
add(i,h);
for(ll i=1;i<=m;i++)
ll x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
if(x==1)
add(y,z);
else
cout<<ask(z)-ask(y-1)<<endl;
return 0;
二.区间修改+单点求和(运用工具差分数组)
https://www.luogu.com.cn/problem/P3368
#include <bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
int n,m,a[maxn],c[maxn],d[maxn];
void add(int p,int x)
while(p<=n)
c[p]+=x,p+=p&-p;
void range_add(int l,int r,int x)
add(l,x),add(r+1,-x);
int ask(int p)
int res=0;
while(p>0)
res+=c[p],p-=p&-p;
return res;
int main()
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
add(i,a[i]-a[i-1]);
for(int i=1;i<=m;i++)
int x,y,z,p;scanf("%d",&x);
if(x==1)
scanf("%d%d%d",&y,&z,&p);
range_add(y,z,p);
else if(x==2)
scanf("%d",&y);
printf("%d\\n",ask(y));
return 0;
以上是关于树状数组 1/30的主要内容,如果未能解决你的问题,请参考以下文章