吊打線段樹的超級樹狀數組

  你是否討厭線段樹那冗長的代碼?你是否還在由於線段樹的難調試而滿頭♂dark汗?那麼,請不要錯過!超級樹狀數組特價!只要998,只要998!數組

##¥……#……¥%……&%¥……ER#%$#$#^T%$^$%函數

  超級樹狀數組,實際上是一種可以支持區間修改和區間查詢的樹狀數組,和線段樹相比,它的常數極小,不須要太多空間,代碼量也少了不少(簡直吊打線段樹)ui

1.樹狀數組spa

既然是超級樹狀數組,那麼就須要一個樹狀數組做爲基礎了。可是在真正實現時,只用到了lowbit()函數(因此說lowbit是樹狀數組的核心啊)調試

2.準備工做code

首先,咱們須要一個差分數組。blog

設a[]數組爲原數組,那麼tree[](差分數組)定義爲tree[i]=a[i]-a[i-1]get

猴子也能一眼看出的性質:a[i]=tree[1]+tree[2]+tree[3]+...+tree[i]數學

3.區間查詢it

(爲何先說查詢呢。。)

(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線段樹你真的能夠當場去世了~

相關文章
相關標籤/搜索