int ID(int l, int r) {
return l + r | l != r;
}
通常情况下,我们都是用rt来保存内容,然后左子树就是rt<<1,右子树就是rt<<1|1
我们仔细想一想,线段树的节点个数其实只有n个,但是为什么我们要开4n内存呢?很明显,有的节点内存并没有用上。
所以我们有么有一种方法,能直接把线段树所有的节点,恰好对应到n个连续空间上呢?
这个ID函数就做到了。有了这个ID函数,我们就没必要向下传递rt,对于每个区间直接用ID取值就行了!
下面是经典的敌兵布阵来演示一下。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]";
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MX = 1e5 + 5;
int sum[MX], n;
inline int ID(int l, int r) {
return l + r | l != r;
}
int build(int l, int r) {
int rt = ID(l, r);
if(l == r) {
scanf("%d", &sum[rt]);
return sum[rt];
}
int m = (l + r) >> 1, w = 0;
w += build(l, m);
w += build(m + 1, r);
return sum[rt] = w;
}
void update(int p, int x, int l, int r) {
int rt = ID(l, r);
sum[rt] += x;
if(l == r) return;
int m = (l + r) >> 1;
if(p <= m) update(p, x, l, m);
else update(p, x, m + 1, r);
}
int query(int L, int R, int l, int r) {
int rt = ID(l, r);
if(L <= l && r <= R) return sum[rt];
int m = (l + r) >> 1, ret = 0;
if(L <= m) ret += query(L, R, l, m);
if(R > m) ret += query(L, R, m + 1, r);
return ret;
}
int main() {
int T, ansk = 0; //FIN;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
build(1, n);
char op[10];
printf("Case %d:\n", ++ansk);
while(scanf("%s", op), op[0] != 'E') {
if(op[0] == 'Q') {
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", query(l, r, 1, n));
} else {
int p, x;
scanf("%d%d", &p, &x);
if(op[0] == 'S') x = -x;
update(p, x, 1, n);
}
}
}
return 0;
}
实际上这就是zkw线段树的用法,只不过用在递归式线段树效果也不错。。