对应线段树,补一下树状数组的笔记
某乎上写的不错的树状数组
1.树状数组原理
蓝线为+ lowbit
绿线为-lowbit
树状数组最重要的原理
树状数组本质上是前缀和(差分)之类的巴拉巴拉
2.lowbit
不理解,背过吧....
int lowbit(int x){
return x&(-x);
}
3.修改点权(加减)
没必要往下传值,类似于线段树,直接在父节点行修改
void build(int x,int v){
for(int i = x; i<=n; i+= lowbit(i)){
tree[i]+=v;
}
}
4.区间求和
前缀和的原理
int query(int s,int e){
int ans1=0,ans2=0;
for(int i = s - 1; i > 0; i-=lowbit(i)) {
ans1+= tree[i];
}
for(int i = e; i > 0; i-=lowbit(i)) {
ans2+=tree[i];
}
return ans2-ans1;
}
树状数组 1模板
//# 树状数组1
#include<iostream>
#include<cstdio>
using namespace std;
const int N=5e5+10;
int tree[N];
int sum[N],a[N];
int n,m;
int lowbit(int x){
return x&(-x);
}
int query(int s,int e){
int ans1=0,ans2=0;
for(int i = s - 1; i > 0; i-=lowbit(i)) {
ans1+= tree[i];
}
for(int i = e; i > 0; i-=lowbit(i)) {
ans2+=tree[i];
}
return ans2-ans1;
}
void build(int x,int v){
for(int i = x; i<=n; i+= lowbit(i)){
tree[i]+=v;
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
add(i,a[i]);
}
for(int i= 1,tpy,x,w; i <=m;i++){
scanf("%d%d%d",&tpy,&x,&w);
if(tpy==1)
build(x,w);
else
printf("%d
",query(x,w));
}
return 0;
}
5.区间加
差分的原理前缀和(貌似不怎么准确)
给x的父亲加上,然后给y+1的父亲减去
这样相当于进行了变区间加的操作一次给x后面的都加k,第二次给y+1后面的都减去k,把x多修改的区间都修回来
ll add(ll x,ll v){
while(x <=n ){
tree[x]+=v;
x+=lowbit(x);
}
}
scanf("%lld%lld%lld",&x,&y,&k);
add(x,k),add(y+1,-k);
//x---y的区间都加+k
数组数组2 模板
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const int N=5e5+10;
ll a[N],tree[N];
int n,m;
ll lowbit(ll x){
return x&(-x);
}
ll add(ll x,ll v){
while(x <=n ){
tree[x]+=v;
x+=lowbit(x);
}
}
ll quert(ll x){
ll ans=0;
while(x>=1){
ans+=tree[x];
x-=lowbit(x);
}
return ans;
}
int main(){
scanf("%lld%lld",&n,&m);
for(int i = 1; i <=n ; i++) {
scanf("%d",&a[i]);
add(i,a[i]-a[i-1]);
}
int tpy;
ll x,y,k;
for(int i = 1;i <= m ;i++){
cin>>tpy;
if(tpy==1){
scanf("%lld%lld%lld",&x,&y,&k);
add(x,k),add(y+1,-k);
}
if(tpy==2){
scanf("%lld",&x);
printf("%lld
",quert(x));
}
}
return 0;
}