NIYAXIMEN

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

树状数组

作用:

动态地维护前缀和查询

Time complexity

修改一个数:$$o(lgn)$$

查询一段区间和:$$o(lgn)$$

实现过程

1 lowbit

返回一个数的二进制下末尾第一个1和后面的0构成的数

如11011000100 返回100=4

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

2 建立树状数组

定义$$t[x]$$保存以下标$$x$$的子树中叶节点的值

有如下几点性质(我不会证明)

1.$$t[x]$$覆盖的长度为$$lowbit(x)$$

2.$$x$$的父节点下标为$$x+lowbit(x)$$

3.$$x$$的左上角的结点下标为$$x-lowbit(x)$$(求前缀和)

4.建成的数的深度为$$log(n)+1$$,因此修改和查询的时间复杂度最差为$$o(logn)$$

那么我们根据这些性质

首先是把数组$$ind$$位置的数加上$$k$$

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

查询下标为$$ind$$的前缀和

long long ask(int x)
{
	long long ans=0;
	for(;x;x-=lowbit(x))
	{
		ans+=t[x];
	}
	return ans;
}

例题:E - Mod Sigma Problem

题目要求

\[\sum_{1\leq l\leq r\leq N} ((\sum_{l\leq i\leq r} A_i)mod M) \]

首先要注意内层的求和要模$$M$$,但外层不要

先定义一个$$s[i]=(a[1]+...+a[i])mod M$$

所以在模$$M$$的意义下的区间和可以表示为

\[s[r]\geq[l-1]\\ (\sum_{l\leq i\leq r} A_i)mod M=s[r]-s[l-1]\\ s[r]<s[l-1]\\ (\sum_{l\leq i\leq r} A_i)mod M=s[r]-s[l-1]+M \]

所以原式可以转化为

\[\sum_{r=1}^{n} \sum_{l=1}^{r}(s[r]-s[l-1])mod M \]

随后我们可以再把$$r$$固定

式子就变成了

\[\sum_{r=1}^{n}(r*s[r]-\sum_{l=1}^{r}(s[l-1])+M*x_r) \]

第二个求和可以直接利用前缀和来处理

此处的关键在于处理这个$$x_r$$,含义为对于每一个$$r$$,第二个求和累加的过程中$$s[r]<s[l-1]$$的个数

为此我们可以用一个树状数组来维护

把$$s[r]$$的值映射为树状数组的下标,$$t[x]$$表示$$s[r]=x$$的个数

当我们遍历一个新的$$r$$时,此时$$t$$数组里储存的说上一此遍历的结果

要求得此时的$$x_r$$只需要求出$$[s[r]+1,m]$$的区间和,即为大于$$s[r]$$的个数---$$x_r$$

注意当$$s[r]$$为$$0$$时不要去加

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m;
long long ans;
long long a[N],t[N],s[N],sl[N];
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int k)
{
	for(;x<=m;x+=lowbit(x))
	{
		t[x]+=k;
	}
}
long long ask(int x)
{
	long long ans=0;
	for(;x;x-=lowbit(x))
	{
		ans+=t[x];
	}
	return ans;
}
int main()
{
	scanf("%d%d",&n,&m);
	long long sum=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		a[i]%=m;
		s[i]=(s[i-1]+a[i])%m;
		sl[i]=sl[i-1]+s[i];
	}
    for(int r=1;r<=n;r++)
    {
    	ans+=s[r]*r-sl[r-1]+(ask(m)-ask(s[r]))*m;
    	if(s[r])
    	add(s[r],1);
	}
	cout<<ans<<endl;
}

posted on 2024-12-01 10:49  AsukaAlice  阅读(6)  评论(0)    收藏  举报