线段树与树状数组
学之前感觉这是两个非常非常难的数据结构,学完才发现也没有想象中那么难,但是题可以出的非常难。
这里就有一些同学坚持认为树状数组没有用,其实树状数组虽然功能少一点,却也是很有优势的。1.常数小;2.代码短;3.内存小;
翻了翻学习资料的文件夹,发现关于这两个数据结构的课件还是比较多的,难度分布也非常的广泛...
树状数组的常规用法:
1 void add (int x,int a) 2 { 3 while (x<=n) 4 { 5 c[x]+=a; 6 x+=lowbit(x); 7 } 8 }
1 int sum(int x) 2 { 3 int S=0; 4 while(x!=0) 5 { 6 S+=c[x]; 7 x-=lowbit(x); 8 } 9 return S; 10 }
初始化一般是一个一个的加,但是其实还有一种方法可以达到$O(N)$的复杂度,非常优越。
1 void init() 2 { 3 memset(c,0,sizeof(c)); 4 for (R i=1;i<=n;++i) 5 { 6 c[i]+=a[i]; 7 if(i+lowbit(i)<=n) 8 c[i+lowbit(i)]+=c[i]; 9 } 10 }
树状数组有一个特别好的用途就是二维树状数组,二维线段树的代码复杂度比一般线段树要大不少,但是二维树状数组只多两行而已。
1 void add(int v,int x,int y) 2 { 3 for (R i=x;i<=n;i+=lowbit(i)) 4 for (R j=y;j<=m;j+=lowbit(j)) 5 t[i][j]+=v; 6 }
1 int ask(int x,int y) 2 { 3 int ans=0; 4 for (R i=x;i;i-=lowbit(i)) 5 for (R j=y;j;j-=lowbit(j)) 6 ans+=t[i][j]; 7 return ans; 8 }
补充一个内容,二维前缀和:
$X_{1},X_{2},Y_{1},Y_{2}(X_{1}<=X_{2},Y_{1}<=Y_{2}) $区域的和:$S=a[X_2][Y_2]-a[X_1-1][Y_2]-a[X_2][Y_1-1]+a[X_1-1][Y_1-1]$