树状数组模板
树状数组
定义与引入:
树状数组处理的大多数问题,线段树都可以处理,但线段树可处理的问题,树状数组不一定可以.
解决问题类型:
单点修改,区间/单点查询;
好像没有太多可说的.
典型例题:
模板:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+20;
int num[N],c[N];//c->主角,树状数组,维护num的前缀和
inline int lowbit(int x)
{
return x&(-x);//此处是取得一个点的管理区间范围 ->x与-x按位与可得x的最大(2^n)因数
}
int sum(int x)
{
int s=0;
while(x)
{
s+=c[x];//加上一个区间和
x-=lowbit(x);//减去一个区间的管理范围
}
return s;
}
void update(int x,int st)//单点修改
{
while(x<=n)//n是输入进来的数据总范围
{
c[x]+=st;
x+=lowbit(x);
}
}
然后由于这个树状数组不能直接维护区间修改,所以有了一维差分树状数组。
它与原先的代码没有区别,只是在我们在某个区间加上一个东西时,去在左边界上加,右边界+1减即可。
但是这个时候它没有办法区间查询了。
怎么办呢,我们维护两个树状数组。
考虑下列式子(设
这俩式子分别维护即可。
这个式子转换还算显然,但是如果我们要求去做一个前缀和的前缀和去统计答案,我们就要复杂些了。
类似于上面,我们看我们要维护的信息,对信息进行转换。
还是三个分别维护三个树状数组即可。
再往高阶前缀和也是一样的,所以k个树状数组可以维护(原式的)k-1阶前缀和。
例题链接
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define qr qr()
#define ps push_back
#define pa pair<int,int>
#define ve vector
#define fi first
#define se second
using namespace std;
const int N=5e5+200;
int n,m,num[N];ll c1[N*2],c2[N*2],c3[N*2];
int nn;
inline ll qr{
ll x=0;char ch=getchar();bool f=0;
while(ch>57||ch<48)f=(ch=='-')?1:0,ch=getchar();
while(ch>=48&&ch<=57)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
inline void add(ll x,int pos){
int tmp=pos;
while(tmp<=nn){
c1[tmp]+=x;
c2[tmp]+=x*pos;
c3[tmp]+=x*pos*pos;
tmp+=tmp&-tmp;
}
}
inline ll ask(int pos){
ll ans=0;int tmp=pos;
while(tmp){
ans+=c1[tmp]*(pos+1)*(pos+2)-c2[tmp]*(pos*2+3)+c3[tmp];
tmp-=tmp&-tmp;
}return ans/2;
}
ve<int>app[N];
void init(){
n=qr;qr;
for(int i=1;i<=n;++i)
num[i]=qr,app[num[i]].ps(i);
nn=2*n+1;
const int wy=n+1;
ll ans=0;
for(int i=0;i<n;++i){
app[i].ps(n+1);
int last=0;
for(unsigned int j=0;j<app[i].size();++j){
int y=2*j-last+wy,x=2*j-(app[i][j]-1)+wy;
ans+=ask(y-1)-(x>=3?ask(x-2):0);
add(1,x);
add(-1,y+1);
last=app[i][j];
}last=0;
for(unsigned int j=0;j<app[i].size();++j){
int y=2*j-last+wy,x=2*j-(app[i][j]-1)+wy;
add(-1,x);
add(1,y+1);
last=app[i][j];
}
}printf("%lld",ans);
}
int main(){
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
init();
return 0;
}
https://www.cnblogs.com/shining-like-stars
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】