【模板】树状数组上的差分数组

数据差分化是一个很神仙也很实用的方法。

具体操作就是将一个数化为多个项的和的形式,这些我们产生的项多为g(x)=f(i)-f(i-1)一类形式,这样可以错位相消去,十分巧妙。

数据差分化有以下神仙之处:

  • 通过差分数据得到原数据g(x):十分显然,g(x)=f(1)+f(2)+f(3)+……+f(x) , ( f(0)=0 )。证明略。

  • 改变区间[ l , r ]的值,只需要进行g(l)=g(l)+k, g(r+1)=g(r+1)-k这样的操作就行了。原因是中间的项全部通过加减抵消了那个加入的k。

因此,维护一个差分化的数据,需要一种能够高效访问区间[ l , r ]的数据结构,那这种数据结构还有什么呢?当然是

线段树&树状数组

对不起我太弱了导致只知道这两个

附上代码(树状数组( 2 ) 的)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline ll qr(){
	char c=getchar();
	ll x=0,q=1;
	while(c<48||c>57)
		q=c==45?-1:q,c=getchar();
	while(c>=48&&c<=57)
		x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return q*x;
}
const int maxn=500000+15;
ll data[maxn];
#define lw(x) (x&(-x))
int n,m;
#define RP(t,a,b) for(int t=(a),edd=(b);t<=edd;t++)
inline void add(int pos,int dataq){
	int t=pos;
	while(t<=n){
		data[t]+=dataq;
		t+=lw(t);
	}
	return;
}
inline ll ask(int x){
	ll ret=0;
	int pos=x;
	while(pos){
		ret+=data[pos];
		pos-=lw(pos);
	}
	return ret;
}
int templ,last;
int t1,t2,t3,t4;
int main(){
	//freopen("in.in","r",stdin);
	//freopen("out.out","w",stdout);
	n=qr();
	m=qr();
	RP(t,1,n){
		templ=qr();
		add(t,templ-last);
		last=templ;
	}
	RP(t,1,m){
		t1=qr();
		if(t1==1){
			t2=qr();
			t3=qr();
			t4=qr();
			add(t2,t4);
			add(t3+1,-t4);
		}
		else{
			t2=qr();
			cout<<ask(t2)<<endl;
		}
	}
	return 0;
}

此类数据结构,应灵活应用,来达到一些神仙的十分之一的水平。

再次感叹我真是太弱了

原文地址:https://www.cnblogs.com/winlere/p/10308104.html