数据差分化是一个很神仙也很实用的方法。
具体操作就是将一个数化为多个项的和的形式,这些我们产生的项多为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;
}
此类数据结构,应灵活应用,来达到一些神仙的十分之一的水平。
再次感叹我真是太弱了