一天一道算法题——线段树

题目【模板】线段树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\n",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 }
View Code

因为一个加号调试了一个晚上o(╥﹏╥)o

posted @ 2020-03-29 20:10  团子好软  阅读(159)  评论(0编辑  收藏  举报