学长的浅谈线段树~~~
#include<cstdio> #include<algorithm> using namespace std; const int N = 1e5 + 10; int T, n, l, r, cas = 0; int f[N * 4]; // f[i]表示i表示的某段区间的和,这种写法的线段树通常需要实际节点数四倍的空间 char s[5]; /* 1 2 3 4 5 6 7 线段树上对应的节点标号 对应于4个人的话,每个节点的区间如下: [1,4] [1,2] [3,4] [1,1] [2,2] [3,3] [4,4] */ void build(int x, int l, int r)//建树 { //x 节点编号 [l,r]节点表示的区间 if (l == r) scanf("%d", &f[x]); else { int mid = (l + r) / 2; //把[l,r]分为[l,mid]和[mid+1,r]两个区间 build(x * 2, l, mid); build(x * 2 + 1, mid + 1, r); f[x] = f[x * 2] + f[x * 2 + 1]; //区间和就是两个子区间的和相加 } } int query(int x, int l, int r, int ll, int rr)//询问区间和 { //如果当前节点x代表的区间[l,r]∈[ll,rr]那么直接返回区间和即可。 //不然递归下去判断左右子区间中是否有[ll,rr]的一部分,并求和。 if (ll <= l&&r <= rr) return f[x]; int mid = (l + r) / 2, res = 0; if (ll <= mid) res += query(x * 2, l, mid, ll, rr); if (rr > mid) res += query(x * 2 + 1, mid + 1, r, ll, rr); return res; } void add(int x, int l, int r, int u, int v)//更新结点的值 { f[x] += v; //让某个节点+v相当于所有包含该节点的区间的和都+v if (l == r) return; int mid = (l + r) / 2; //判断在该区间的左子区间还是右子区间 if (u <= mid) add(x * 2, l, mid, u, v); else add(x * 2 + 1, mid + 1, r, u, v); } int main() { scanf("%d", &T); while (T--) { scanf("%d", &n); build(1, 1, n); //初始化线段树上各节点的值 printf("Case %d: ", ++cas); while (scanf("%s", s), s[0] != 'E') { scanf("%d%d", &l, &r); if (s[0] == 'Q') printf("%d ", query(1, 1, n, l, r)); if (s[0] == 'A') add(1, 1, n, l, r); if (s[0] == 'S') add(1, 1, n, l, -r); } } return 0; }