poj3468的问题描述:
给定一组数字A1, A2, ..., AN,在这个数组上有两种操作:
(1)C a b c,将数字c加到区间[a,b]表示的每一个数上
(2)Q a b,查询区间[a,b]表示的所有数的和,输出这个和值。
注意,和值有可能大于2的32次方。
线段树的代码:
#include <stdio.h> #define LEN 100000 typedef __int64 int64; typedef struct segment { int l; int r; int64 sum; int64 add; }segment; segment s[LEN*3]; int64 sum; int64 reverse_sum; /* * S_init * 构造线段树 * [l, r] - 节点区间 * index - 存储位置 */ void S_init(int l, int r, int index) { int mid; s[index].l = l; s[index].r = r; s[index].sum = 0; s[index].add = 0; if (l == r) return; mid = (l + r) >> 1; S_init(l, mid, index*2); // 左孩子 S_init(mid+1, r, index*2+1);// 右孩子 } /* * S_insert * 将数据插入到线段树 * p - 数据的位置 * d - 数据 */ void S_insert(int l, int r, int index, int p, int d) { int mid = 0; if (l <= p && p <= r) // p在线段上 s[index].sum += d; if (l == r)return; mid = (l + r) >> 1; if (mid >= p) // 左孩子 S_insert(l, mid, index*2, p, d); else S_insert(mid+1, r, index*2+1, p, d); } void S_addReverse(int index, int64 d) { while (index != 0) { s[index].sum += d; index /= 2; } } void S_add(int l, int r, int index, int a, int b, int d) { int mid = 0; int64 ss; if (a == l && r == b) // [l,r] = [a,b] { s[index].add += d; ss = (b - a + 1) * d; S_addReverse(index/2, ss); return; } mid = (l + r) >> 1; if (mid >= b) S_add(l, mid, index*2, a, b, d); else if (mid < a) S_add(mid+1, r, index*2+1, a, b, d); else { S_add(l, mid, index*2, a, mid, d); S_add(mid+1, r, index*2+1, mid+1, b, d); } } /* * S_reverse * 反向查找 * */ void S_reverse(int index) { while (index != 0) { reverse_sum += s[index].add; index /= 2; } } void S_query(int l, int r, int index, int a, int b) { int mid = 0; if (l == a && r == b) // { sum += s[index].sum; reverse_sum = 0; S_reverse(index); sum += reverse_sum * (b + 1 - a); return; } if (l == r) return; mid = (l + r) >> 1; if (mid >= b) S_query(l, mid, index*2, a, b); else if (mid < a) S_query(mid+1, r, index*2+1, a, b); else // 分开 { S_query(l, mid, index*2, a, mid); S_query(mid+1, r, index*2+1, mid+1, b); } } int main() { int n, m; int i; int a, b, d; char str[2]; scanf("%d %d", &n, &m); S_init(1, n, 1); for (i=0; i<n; i++) { scanf("%d", &d); S_insert(1, n, 1, i+1, d); } while (m--) { scanf("%s %d %d", str, &a, &b); if (str[0] == 'Q') { sum = 0; S_query(1, n, 1, a, b); printf("%I64d/n", sum); } else { scanf("%d", &d); S_add(1, n, 1, a, b, d); } } return 0; }
其中,为了提高检索的效率,引入了S_addReverse函数。