zoukankan      html  css  js  c++  java
  • 一天一道算法题——线段树

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

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

  • 相关阅读:
    git爬坑不完全指北(二):failed to push some refs to ‘XXX’的解决方案
    javascript精雕细琢(三):作用域与作用域链
    javascript精雕细琢(二):++、--那点事
    git爬坑不完全指北(一):Permission to xxx.git denied to user的解决方案
    深入浅出CSS(三):隐藏BOSS大盘点之默认属性小总结
    读书笔记
    MPP5运维手册
    HTML自闭合(self-closing)标签
    Mysql JDBC的通信协议(报文的格式和基本类型)
    详解 & 0xff 的作用
  • 原文地址:https://www.cnblogs.com/zyyz1126/p/12594446.html
Copyright © 2011-2022 走看看