线段树模板1 [Luogu P3372]
代码+注释:
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 5 int n, q, flag, x, y, v; 6 int a[100010]; 7 struct node{ 8 long long a, b; 9 }tree[400010]; //树,a为数据域,b为标记 10 11 void build_tree(int now, int l, int r) { //建树 12 if (l == r) { 13 tree[now].a = a[l]; //填充数据 14 return ; 15 } 16 int mid = (l + r) >> 1; //mid = (l + r) div 2; 位运算加速 17 build_tree(now + now, l, mid); //往左边继续建树 18 build_tree(now + now + 1, mid + 1, r); //往右边继续建树 19 tree[now].a = tree[now + now].a + tree[now + now + 1].a; //此时节点数据域为下接两个节点的和,便于查询 20 } 21 22 void plust(int now, int l, int r, int x, int y) {//区间加操作 23 if ((l == x) && (r == y) || (l == r)) { //达到要求 24 tree[now].a += v * (r - l + 1); //累加v的值与当前节点下所有的节点数的积(若当前节点下没有节点则为1) 25 tree[now].b += v; //打标记 26 return ; //回溯 27 } 28 int mid = (l + r) >> 1; 29 tree[now + now].b += tree[now].b; //向下传递标记(以下都是) 30 tree[now + now + 1].b += tree[now].b; 31 tree[now + now].a += (tree[now].b * (mid - l + 1)); 32 tree[now + now + 1].a += (tree[now].b * (r - mid)); 33 tree[now].b = 0; //向下传递标记,当前标记清空(不管怎么样就是这样) 34 if (y <= mid) plust(now + now, l, mid, x, y);//若操作区间在mid左边,往左边继续操作 35 else if (x > mid) plust(now + now + 1, mid + 1, r, x, y);//若在mid右边,往右边继续操作 36 else { //否则拆开分别左右操作 37 plust(now + now, l, mid, x, mid); 38 plust(now + now + 1, mid + 1, r, mid + 1, y); 39 } 40 tree[now].a = tree[now + now].a + tree[now + now + 1].a; //更新当前节点的数据 41 } 42 43 long long query(int now, int l, int r, int x, int y) { //区间查询 44 if ((l == x) && (r == y)) return tree[now].a; //若当前节点所代表的区间恰好与需要查询的区间重合,返回值 45 int mid = (l + r) >> 1; 46 tree[now + now].b += tree[now].b; //同上,向下传递标记(以下都是) 47 tree[now + now + 1].b += tree[now].b; 48 tree[now + now].a += (tree[now].b * (mid - l + 1)); 49 tree[now + now + 1].a += (tree[now].b * (r - mid)); 50 tree[now].b = 0; //同上,向下传递标记 51 if (y <= mid) return query(now + now, l, mid, x, y); //查询区间在mid左边,往左边取 52 else if (x > mid) return query(now + now + 1, mid + 1, r, x, y); //否则在右边取 53 else return query(now + now, l, mid, x, mid) + query(now + now + 1, mid + 1, r, mid + 1, y); //再否则断开从左右边取 54 } 55 56 int main() { //主程序 57 scanf("%d%d", &n, &q); //读入数列的长度和操作的次数 58 for (int i = 1; i <= n; i++) 59 scanf("%d", &a[i]); 60 61 build_tree(1, 1, n); //建树 62 63 for (int i = 1; i <= q; i++) { 64 scanf("%d%d%d", &flag, &x, &y); //开始 65 if (flag == 1) { 66 scanf("%d", &v); //v为要加进去的数 67 plust(1, 1, n, x, y); //区间加操作 68 continue; 69 } 70 printf("%lld\n", query(1, 1, n, x, y)); //否则查询区间 71 } 72 73 return 0; 74 }
供个人复习使用