3.21
线段树
堆还没写好,就要被赶着去学线段树了。我们通过一道基础题进行线段树的引入
线段树模板
thinking
线段树用法,如题,如果我们采用前缀和进行查询区间的和,当发生修改的时候,我们需要对包括该部分区间的所有前缀值进行修改,不可避免地\(n^2\),而线段树通过对区间建树求和,复杂度降到了\(log n\)。
我们使用完全二叉树进行建树操作,对于这个二叉树,我们只有两种操作,单点修改(add()),区间查询(calc()),由于二叉树地性质,我们均采用递归地形式进行书写
- buildtree
/*
从k开始,对从l到r地区间进行建树
左子树表示[l,m]的和
右子树表示[m+1,r]的和
*/
inline void buildtree(int k, int l, int r) {
if (l == r) {
f[k] = a[l];
return;
}
int m = (l + r) >> 1;
buildtree(k + k, l, m);
buildtree(k + k + 1, m + 1, r);
f[k] = f[k + k] + f[k + k + 1];
}
- add
/*
从k开始,对区间[l,r]的x下标,加上y
如果对于某一个数进行加上操作,则从跟节点到叶节点这一条路径都需要加和,我们只需判断每一次x再左子树还是右子树即可。
*/
inline void add(int k, int l, int r, int x, int y) {
f[k] += y;
if (l == r)
return;
int m = (l + r) >> 1;
if (x <= m)
add(k + k, l, m, x, y);
else
add(k + k + 1, m + 1, r, x, y);
}
- calc
/*
从k开始,在区间[l,r],对[s,t]区间进行求和
查询区间和有如下几种情况:
1、[l,s]与[s,t]完全相同,直接返回节点值即可
2、区间不匹配
2.1、在左半区间内,进行递归搜索即可
2.2、在右半区间内,进行递归搜索即可
2.3、横跨了中点分开的两个区间,将区间从中点分两半,分别进行递归求和。
*/
int calc(int k, int l, int r, int s, int t) {
if (l == s && r == t)
return f[k];
int m = (l + r) >> 1;
if (t <= m)
return calc(k + k, l, m, s, t);
else if (s > m)
return calc(k + k + 1, m + 1, r, s, t);
else
return calc(k + k, l, m, s, m) + calc(k + k + 1, m + 1, r, m+1, t);
}
solution
const int N = 5*1e5;
int a[N + 5], f[4 * N + 4];
inline void buildtree(int k, int l, int r) {
if (l == r) {
f[k] = a[l];
return;
}
int m = (l + r) >> 1;
buildtree(k + k, l, m);
buildtree(k + k + 1, m + 1, r);
f[k] = f[k + k] + f[k + k + 1];
}
inline void add(int k, int l, int r, int x, int y) {
f[k] += y;
if (l == r)
return;
int m = (l + r) >> 1;
if (x <= m)
add(k + k, l, m, x, y);
else
add(k + k + 1, m + 1, r, x, y);
}
int calc(int k, int l, int r, int s, int t) {
if (l == s && r == t)
return f[k];
int m = (l + r) >> 1;
if (t <= m)
return calc(k + k, l, m, s, t);
else if (s > m)
return calc(k + k + 1, m + 1, r, s, t);
else
return calc(k + k, l, m, s, m) + calc(k + k + 1, m + 1, r, m+1, t);
}
void solve() {
int n, m; cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> a[i];
buildtree(1, 1, n);
for (int i = 0; i < m; ++i) {
int index; cin >> index;
if (index == 1) {
int x, k; cin >> x >> k;
add(1, 1, n, x, k);
}
else {
int x, y; cin >> x >> y;
cout << calc(1, 1, n, x, y) << '\n';
}
}
}

浙公网安备 33010602011771号