树状数组模板

单点修改,区间询问模板

add(x,k),相当于 a[x]+=k

get(x) 相当于 pre[x]

int c[MAXN];

inline int lowbit(const int &x){return x&-x;}

void add(int x,int k)
{
    while(x<=n)
    {
        c[x]+=k;
        x+=lowbit(x);
    }
}

int get(int x)
{
    int ret=0;
    while(x)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}

void init()
{
    int x;
    for(int i=1;i<=n;i++)
    {
        c[i]+=a[i];
        x=i+lowbit(i);
        if(x<=n) c[x]+=c[i];
    }
}

区间修改,单点查询模板

运用了差分大法

add(l,r,x) ,是给 a[l]a[r] 的所有数加 x

get(x) ,是查询 a[x] 的值

int c[MAXN];

inline int lowbit(const int &x){return x&-x;}

void repreadd(int x,int k)
{
    while(x<=n)
    {
        c[x]+=k;
        x+=lowbit(x);
    }
}

void add(int l,int r,int x)
{
    add(l,x),add(r+1,-x);
}

int get(int x)
{
    int ret=0;
    while(x)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}

void init()
{
    int x;
    for(int i=1;i<=n;i++)
    {
        c[i]+=a[i]-a[i-1];
        x=i+lowbit(i);
        if(x<=n) c[x]+=c[i];
    }
}

区间修改,区间查询模板

说实话,这种用法算不上模板,但确实很强,比用线段树快很多,空间少用了很多,最重要的是:

代码量极其之短,而且特别好调(只要公式没写错)

\(a_i\) 为原数组, \(b_i\)\(a_i\) 的差分数组

可得:

\[a_i=\sum\limits_{j=1}^ib_j \]

因此,如果我们想要求出前 \(x\) 个数之和,可得:

\[\sum\limits_{i=1}^xa_i\\ =\sum\limits_{i=1}^x\sum\limits_{j=1}^ib_j\\ =b_1\times x+b_2\times(x-1)+b_3\times(x-2)+\cdots+b_x\times1\\ =\sum\limits_{i=1}^x(x-i+1)b_i\\ =(x+1)\sum\limits_{i=1}^xb_i-\sum\limits_{i=1}^xi \times b_i \]

这时候就可以发现,要想求出区间之和,需要维护两个树状数组,一个统计 \(b_i\) 的前缀和,另一个统计 \(i \times b_i\) 的前缀和。

int n;
ll c1[MAXN],c2[MAXN],a[MAXN];

inline int lowbit(int x){return x&-x;}

void stdadd(int x,ll k)
{
	ll w=x*k;
	while(x<=n)
	{
		c1[x]+=k,c2[x]+=w;
		x+=lowbit(x);
	}
}

ll stdgetsum(ll *c,int x)
{
	ll ret=0;
	while(x)
	{
		ret+=c[x];
		x-=lowbit(x);
	}
	return ret;
}

void add(int l,int r,int x)
{
	stdadd(l,x);
	stdadd(r+1,-x);
}

ll getsum(int l,int r)
{
	return (r+1)*stdgetsum(c1,r)-l*stdgetsum(c1,l-1)-
	stdgetsum(c2,r)+stdgetsum(c2,l-1);
}

void init()
{
    for(int i=1;i<=n;i++)
    {
        c1[i]+=a[i]-a[i-1];
        c2[i]+=i*(a[i]-a[i-1]);
        int x=i+lowbit(i);
        if(x<=n)
        {
            c1[x]+=c1[i];
            c2[x]+=c2[i];
        }
    }
}
posted @ 2021-11-19 14:34  yhang323  阅读(24)  评论(0编辑  收藏  举报