树状数组1

树状数组1

基操:

void in(int x,int val)
{
	for(int i=x;i<=n;i+=(i&(-i)))  tr1[i]+=val;
} 

int ask(int x)
{
	int ans=0;
	for(int i=x;i;i-=(i&(-i)))	ans+=tr[i];
	return ans;
}

1,单点修改,区间查询:

for(int i=1;i<=n;i++)    in(a[i]);
in(x,val);
ask(r)-ask(l-1);

2.区间修改,单点查询:

差分;

for(int i=1;i<=n;i++)  in(i,a[i]-a[i-1]);
in(l,x),in(r+1,-x);
cout<

3.区间修改,区间查询:

维护两个树状数组;

\(\displaystyle a[i]= \sum _{i=1}^{r}c[i]\)

\(\displaystyle \sum _{i=1}^{n}a[i]=\sum_{i=1}^{n} \sum_{j=1}^{i}c[i]=n \times c[1]+(n-1) \times c[2]+…+(n-(n-1)) \times c[n]=n \times \sum _{i=1}^{n}c[i]- \sum_{i=1}^{n}(i-1) \times c[i]\)

\(\displaystyle \sum _{i=l}^{r}=r \times \sum _{i=1}^{r}c[i]- \sum_{i=1}^{r}(i-1) \times c[i]-((l-1) \times \sum _{i=1}^{l-1}c[i]- \sum_{i-1}^{l-1}(i-1) \times c[i])\)

故一个维护前缀和,一个维护\(\sum(i-1)*c[i]\)

#include
#include
#include
#include
#include
using namespace std;

#define ll long long

ll read()
{
	ll w=0,f=1;char ch;
	while(!(isdigit(ch=getchar())))    (ch=='-')&&(f=-f);
	for(w=(ch^48);isdigit(ch=getchar());w=(w<<1)+(w<<3)+(ch^48));
	return w*f;
}

const int N=1e6+10;
int n,q;
ll tr1[N],tr2[N];

void in(int x,ll val)
{
	for(int i=x;i<=n;i+=(i&(-i)))
	{
		tr1[i]+=val;
		tr2[i]+=(x-1)*val;
	}
} 

ll ask(int x)
{
	ll ans=0;
	for(int i=x;i;i-=(i&(-i)))	ans=ans+x*tr1[i]-tr2[i];
	return ans;
}

int main()
{
	scanf("%d%d",&n,&q);
	ll x,y=0;
	for(int i=1;i<=n;i++)   
	{
		x=read(); y=x-y;
		in(i,y);
		y=x;
	} 
	
	for(int i=1;i<=q;i++)
	{
		int opt=read();
		if(opt==1)	
		{
			int l=read(),r=read(),x=read();
			in(l,x),in(r+1,-x);//r+1处要减r*x。即-(x*(l-1)+x*(r-l+1)*x)
		}
		else  
		{
			int l=read(),r=read();
			printf("%lld\n",ask(r)-ask(l-1));
		}
	}
	return 0;
}

你可能感兴趣的:(树状数组1)