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

题目: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_s("%d%d", &n, &m);
57     for (int i = 1; i <= n; i++)
58         scanf_s("%lld", &num[i]);
59     buildTree(1, n, root);
60     while (m--) {
61         cin >> k;
62         if (k == 1) {
63             scanf_s("%d%d%d", &x, &y, &k);
64             if(x<=y)
65                 add(x, y, k, root);
66         }
67         else {
68             scanf_s("%d%d", &x, &y);
69             if (x <= y)
70                 printf_s("%lld\n",print(x,y,root));
71         }
72     }
73     return 0;
74 }

ε=(´ο`*)))唉

猜你喜欢

转载自www.cnblogs.com/zyyz1126/p/12594446.html
今日推荐