题目【模板】线段树1:https://www.luogu.com.cn/problem/P3372
RMQ问题(Range Minimum/Maximum Query)和求区间和的问题可以用暴力法做,时间复杂度为O(n^2),用在本题会超时,所以我们选择线段树做。
线段树是一种用于区间操作的数据结构,用二叉树构造。如图。
线段树的每个节点代表了一个区间。
防止超时,用了lazy标记。
1 #include<iostream> 2 #include<stdio.h> 3 #define maxn 100010 4 typedef long long ll; 5 using namespace std; 6 7 struct node { 8 ll l, r, sum; 9 } tree[maxn<<2+2]; 10 int n, root = 1; 11 ll num[maxn+2], addv[maxn << 2+2];//addv可以放在node里面 12 void pushUp(int x) { 13 tree[x].sum = tree[x << 1].sum + tree[x << 1 | 1].sum;//x << 1 | 1 means (x<<1)+1 14 } 15 void pushDown(int x) { 16 if (addv[x]) { 17 addv[x << 1] += addv[x]; 18 addv[x << 1 | 1] += addv[x]; 19 tree[x << 1].sum += addv[x]*(tree[x<<1].r-tree[x<<1].l+1); 20 tree[x << 1 | 1].sum += addv[x]*(tree[x << 1|1].r - tree[x<<1|1].l + 1); 21 addv[x] = 0; 22 } 23 } 24 void buildTree(int l,int r,int x) { 25 tree[x].l = l, tree[x].r = r; 26 if (l == r) { tree[x].sum = num[l]; return; } 27 int mid = (l + r) >> 1; 28 buildTree(l, mid, x << 1); 29 buildTree(mid + 1, r, (x << 1) + 1); 30 pushUp(x); 31 } 32 void add(int l, int r, int k, int x) { 33 if (l<= tree[x].l && r>= tree[x].r) { 34 tree[x].sum += (tree[x].r-tree[x].l + 1)*(ll)k; 35 addv[x] += k; 36 return; 37 } 38 pushDown(x); 39 int mid = (tree[x].l + tree[x].r) >> 1; 40 if (l <= mid) add(l, r, k, x << 1); 41 if (r > mid)add(l, r, k, x << 1 | 1); 42 pushUp(x); 43 } 44 ll print(int l, int r,int x) { 45 if (l <= tree[x].l && r >= tree[x].r) 46 return tree[x].sum; 47 pushDown(x); 48 ll sum = 0; 49 int mid = (tree[x].l + tree[x].r) >> 1; 50 if (l <= mid)sum += print(l,r,x<<1); 51 if (r > mid)sum += print(l, r, x << 1 | 1); 52 return sum; 53 } 54 int main() { 55 int m, k, x, y; 56 scanf("%d%d", &n, &m); 57 for (int i = 1; i <= n; i++) 58 scanf("%lld", &num[i]); 59 buildTree(1, n, root); 60 while (m--) { 61 cin >> k; 62 if (k == 1) { 63 scanf("%d%d%d", &x, &y, &k); 64 if(x<=y) 65 add(x, y, k, root); 66 } 67 else { 68 scanf("%d%d", &x, &y); 69 if (x <= y) 70 printf("%lld ",print(x,y,root)); 71 } 72 } 73 return 0; 74 }
ε=(´ο`*)))唉
题目2【模板】线段树2:https://i-beta.cnblogs.com/posts/edit;postId=12594446
比上面多了一个求区间乘法。
需要考虑清楚乘法和加法谁先谁后的关系。

1 #include<iostream> 2 #include<stdio.h> 3 #define maxn 100010 4 typedef long long ll; 5 using namespace std; 6 7 struct node { 8 ll sum; 9 int l, r; 10 } tree[maxn<<2]; 11 int n, root = 1,p; 12 ll num[maxn], addv[maxn << 2], mult[maxn << 2]; 13 void pushUp(int x) { 14 tree[x].sum = (tree[x << 1].sum + tree[x << 1|1].sum)%p;//x << 1 | 1 means (x<<1)+1 15 } 16 void pushDown(int x) { 17 tree[x << 1].sum = (mult[x] * tree[x << 1].sum + (addv[x] * (tree[x << 1].r - tree[x << 1].l + 1))%p) % p; 18 tree[x << 1 | 1].sum = (mult[x] * tree[x << 1 | 1].sum + (addv[x] * (tree[x << 1 | 1].r - tree[x << 1 | 1].l + 1))%p) % p; 19 mult[x << 1] = (mult[x << 1]*mult[x])%p; 20 mult[x << 1 | 1] = (mult[x << 1|1] * mult[x]) % p; 21 addv[x << 1] = (addv[x << 1]*mult[x] + addv[x]) % p; 22 addv[x << 1 | 1] = (addv[x << 1|1]*mult[x] + addv[x]) % p; 23 mult[x] = 1, addv[x] = 0; 24 } 25 void buildTree(int l,int r,int x) { 26 tree[x].l = l, tree[x].r = r; mult[x] = 1; 27 if (l == r) { tree[x].sum = num[l]%p; return; } 28 int mid = (l + r) >> 1; 29 buildTree(l, mid, x << 1); 30 buildTree(mid + 1, r, x << 1|1); 31 pushUp(x); 32 } 33 void add(int l, int r, int k, int x) { 34 if (l<= tree[x].l && r>= tree[x].r) { 35 tree[x].sum = (tree[x].sum + k * (tree[x].r - tree[x].l + 1))%p; 36 addv[x] = (addv[x] + k) % p; 37 return; 38 } 39 pushDown(x); 40 int mid = (tree[x].l + tree[x].r) >> 1; 41 if (l <= mid) add(l, r, k, x << 1); 42 if (r > mid)add(l, r, k, x << 1 | 1); 43 pushUp(x); 44 } 45 void multiply(int l, int r, int k, int x) { 46 if (l <= tree[x].l&&r >= tree[x].r) { 47 tree[x].sum = (tree[x].sum*k) % p; 48 addv[x] = (addv[x] * k) % p; 49 mult[x] = (mult[x] * k) % p; 50 return; 51 } 52 pushDown(x); 53 int mid = (tree[x].l + tree[x].r) >> 1; 54 if (l <= mid)multiply(l, r, k, x << 1); 55 if (r > mid)multiply(l, r, k, x << 1 | 1); 56 pushUp(x); 57 } 58 ll print(int l, int r,int x) { 59 if (l <= tree[x].l && r >= tree[x].r) 60 return tree[x].sum; 61 pushDown(x); 62 ll sum = 0; 63 int mid = (tree[x].l + tree[x].r) >> 1; 64 if (l <= mid)sum = (sum+print(l,r,x<<1))%p; 65 if (r > mid)sum = (sum+print(l, r, x << 1 | 1))%p; 66 return sum; 67 } 68 int main() { 69 int m, k, x, y; 70 scanf("%d%d%d", &n, &m,&p); 71 for (int i = 1; i <= n; i++) 72 scanf("%lld", &num[i]); 73 buildTree(1, n, root); 74 while (m--) { 75 cin >> k; 76 if (k == 2) { 77 scanf("%d%d%d", &x, &y, &k); 78 if(x<=y) 79 add(x, y, k, root); 80 } 81 else if (k == 1) { 82 scanf("%d%d%d", &x, &y, &k); 83 if (x <= y) 84 multiply(x, y, k, root); 85 } 86 else { 87 scanf("%d%d", &x, &y); 88 if (x <= y) 89 cout << print(x, y, root) % p << endl; 90 } 91 } 92 return 0; 93 }
因为一个加号调试了一个晚上o(╥﹏╥)o