嘘~ 正在从服务器偷取页面 . . .

线段树空间开4倍的原因


线段树空间开4倍的原因

如果证明有错欢迎指出。

对于长为 \(n\) 的序列,显然以其构建的线段树有 \(n\) 个叶子节点

此时线段树的高度为 \(k=\left\lceil{\log_2 n}\right\rceil+1\) (第一层的高度为 \(1\)

通过等比数列求和公式 \[ \begin{aligned} S_n= \begin{cases} na_1,&q=1 \\\\ \dfrac{a_1\left(1-q^n\right)}{1-q} = \dfrac{a_1-a_nq}{1-q} ,&q\ne 1 \end{cases} \end{aligned} \] 可知

至多有 \(\dfrac{1\times(1-2^k)}{1-2} = 2^k-1\) 个结点

即有 \(2^{\left\lceil{\log_2 n}\right\rceil+1}-1\) 个结点

根据 \[ \begin{aligned} &\left\lceil{x}\right\rceil- \left\lfloor{x}\right\rfloor=\begin{cases} 0,&\text{if } x \in \mathbb{Z},\\\\ 1,&\text{if }x \notin \mathbb{Z}. \end{cases}\end{aligned} \] 可知

  • \(\log_2 n\) 为整数时,结点数为 \(2n-1\) 个节点

  • \(\log_2 n\) 不为整数时,结点数为 \(4 \times 2^{\left\lfloor{\log_2 n}\right\rfloor}-1\)

    \(\because \left\lfloor{\log_2 n}\right\rfloor < \log_2 n\)

    \(\therefore 4 \times 2^{\left\lfloor{\log_2 n}\right\rfloor}-1 < 4n-1 < 4n\)

很多时候 \(n\) 并不恰好为 \(2^k\) ,因此开 \(4\) 倍空间正好

值得注意的是,对于 ls(at) = at*2 的这种写法

一定要避免在叶子结点调用 ls(at)

因为此时有可能会越界到 \(8n\) 的位置

这里贴一个线段树1的代码 卡了点常啥的,无视它(逃

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e5+15)
char buf1[SIZ],*p1,*p2;
char readchar()
{
    if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
    return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    static T stk[66];T top=0;
    do{stk[top++]=k%10,k/=10;}while(k);
    while(top){pc(stk[--top]+'0');}
}
#define N (int)(1e5+15)
int n,Q;
int a[N];
struct node
{
    int sum,tag;
}t[N<<2];
#define ls(at) (at<<1)
#define rs(at) (at<<1|1)
void push_up(int at)
{
    t[at].sum=t[ls(at)].sum+t[rs(at)].sum;
}
void build(int l,int r,int at)
{
    if(l==r)
    {
        t[at].sum=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,ls(at));
    build(mid+1,r,rs(at));
    push_up(at);
}
void proc(int l,int r,int k,int at)
{
    t[at].sum+=k*(r-l+1);
    t[at].tag+=k;
}
void push_down(int l,int r,int at)
{
    if(t[at].tag)
    {
        int mid=(l+r)>>1;
        proc(l,mid,t[at].tag,ls(at));
        proc(mid+1,r,t[at].tag,rs(at));
    }
    t[at].tag=0;
}
void update(int nl,int nr,int l,int r,int k,int at)
{
    if(nl<=l&&r<=nr)
    {
        t[at].sum+=k*(r-l+1);
        t[at].tag+=k;
        return;
    }
    int mid=(l+r)>>1;
    push_down(l,r,at);
    if(nl<=mid)update(nl,nr,l,mid,k,ls(at));
    if(nr>mid)update(nl,nr,mid+1,r,k,rs(at));
    push_up(at);
}
int query(int nl,int nr,int l,int r,int at)
{
    if(nl<=l&&r<=nr)
        {return t[at].sum;}
    int mid=(l+r)>>1,res=0;
    push_down(l,r,at);
    if(nl<=mid)res+=query(nl,nr,l,mid,ls(at));
    if(nr>mid)res+=query(nl,nr,mid+1,r,rs(at));
    return res;
}
signed main()
{
    read(n);read(Q);
    for(int i=1; i<=n; i++)
        read(a[i]);
    build(1,n,1);
    while(Q--)
    {
        int op,l,r,k;
        read(op);
        if(op==1)
        {
            read(l);read(r);read(k);
            update(l,r,1,n,k,1);
        }else
        {
            read(l);read(r);
            write(query(l,r,1,n,1));pc('\n');
        }
    }
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录