高级数据结构-线段树

news2025/2/2 4:53:39

线段树

线段树树基于分治思想的二叉树,用来维护区间信息(区间和、区间最大值、区间最小值等等)。可以在 O ( l o g n ) O(logn) O(logn)的时间内完成区间信息的查询和修改。

  • 线段树中每个叶子结点存储元素本身,非叶子结点存储区间内元素的统计值

image-20230612160951014

节点数组tr[]

l,r存区间的左右端点,sum存区间和

int n,w[N];
struct node{
  int l,r,sum;
}tr[N*4];//注意需要开四倍空间

递归建树

父节点的编号为p

左孩子编号为2*p,右孩子编号为2*p+1

#define lc p<<1
#define rc p<<1|1 或者2*p+1

void build(int p,int l,int r){
  tr[p]={l,r,w[l]};
  if(l==r) return;//是叶子结点了,直接返回
  int mid=l+r>>1;
  build(lc,l,mid);
  build(rc,mid+1,r);
  tr[p].sum=tr[lc].sum+tr[rc].sum;
}

单点修改

从根节点进入,递归找到叶子结点[x,x],把该结点的值增加k,然后从下往上更新其祖先节点上的统计值。

void update(int p,int x,int k){//将x位置上的数加k
  if(tr[p].l==x && tr[p].r==x){
    tr[p].sum+=k;
    return;
  }
  int mid=l+r>>1;
  if(x<=mid) update(lc,x,k); //只会进入一个分支
  else update(rc,x,k);
  tr[p].sum=tr[lc].sum+tr[rc].sum;
}

image-20230612162228410

区间查询

区间查询使用拆分和拼凑的思想,例如,查询区间[4,9]可以拆分为[4,5],[6,8],[9,9],通过合并这三个区间的答案来求查询的答案。

从根节点进入,递归执行以下过程:

  1. 若查询区间[x,y]完全覆盖当前区间,则立即回溯,并返回该结点的sum值
  2. 若左子节点与[x,y]有重叠,则递归访问左子树
  3. 若右子节点与[x,y]有重叠,则递归访问右子树
int query(int p,int x,int y){
  if(x<=tr[p].l &&tr[p].r<=y)return tr[p].sum;
  int mid=tr[p].l+tr[p].r>>1;
  int sum=0;
  if(x<=mid) sum+=query(lc,x,y);
  if(y>mid) sum+=query(rc,x,y);
  return sum;
}

image-20230612163124639

区间修改

例如对区间[4,5]内的每个数加上5,如果修改区间[x,y]所覆盖的每个叶子结点,时间是 O ( n ) O(n) O(n)

可以做懒惰修改,当[x,y]完全覆盖节点区间[a,b]时,先修改区间的sum值,然后打上一个懒标记,然后立即返回,等下次需要的时候,再下传懒标记,这样可以把修改和查询的时间都控制在 O ( l o g n ) O(logn) O(logn)

void pushup(int p){
  tr[p].sum=tr[lc].sum+tr[rc].sum;
}

void pushdown(int p){
  if(tr[p].add){
    tr[lc].sum+=tr[p].add* (tr[lc].r-tr[lc].l+1);
    tr[rc].sum+=tr[p].add* (tr[rc].r-tr[rc].l+1);
    tr[lc].add+=tr[p].add;
    tr[rc].add+=tr[p].add;
    tr[p].add=0;
  }
}

void update(int p,int x,int y,int k){
  if(x<=tr[p].l &&tr[p].r<=y){
    tr[p].sum+=(tr[p].r-tr[p].l+1)*k;
    tr[p].add+=k;
    return;
  }
  int m=tr[p].l+tr[p].r>>1;
  pushdown(p);
  if(x<=m) update(lc,x,y,k);
  if(y>m) update(rc,x,y,k);
  pushup(p);
}

【模板】树状数组 1

链接:https://www.luogu.com.cn/problem/P3374

题目描述

如题,已知一个数列,你需要进行下面两种操作:

  • 将某一个数加上 x x x

  • 求出某区间每一个数的和

输入格式

第一行包含两个正整数 n , m n,m n,m,分别表示该数列数字的个数和操作的总个数。

第二行包含 n n n 个用空格分隔的整数,其中第 i i i 个数字表示数列第 i i i 项的初始值。

接下来 m m m 行每行包含 3 3 3 个整数,表示一个操作,具体如下:

  • 1 x k 含义:将第 x x x 个数加上 k k k

  • 2 x y 含义:输出区间 [ x , y ] [x,y] [x,y] 内每个数的和

输出格式

输出包含若干行整数,即为所有操作 2 2 2 的结果。

样例 #1

样例输入 #1

5 5
1 5 4 2 3
1 1 3
2 2 5
1 3 -1
1 4 2
2 1 4

样例输出 #1

14
16

提示

【数据范围】

对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 8 1 \le n \le 8 1n8 1 ≤ m ≤ 10 1\le m \le 10 1m10
对于 70 % 70\% 70% 的数据, 1 ≤ n , m ≤ 1 0 4 1\le n,m \le 10^4 1n,m104
对于 100 % 100\% 100% 的数据, 1 ≤ n , m ≤ 5 × 1 0 5 1\le n,m \le 5\times 10^5 1n,m5×105

代码

#include <bits/stdc++.h>
#define int long long
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
#define debug(s, x) cout << "#debug:(" << s << ")=" << x << endl;
using namespace std;

#define lc p << 1
#define rc p << 1 | 1
const int N = 5e5 + 10;

struct tr {
    int l, r, sum;
} tr[N * 4];
int w[N];
void build(int p, int l, int r) {
    tr[p] = {l, r, w[l]};
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    build(lc, l, mid);
    build(rc, mid + 1, r);
    tr[p].sum = tr[lc].sum + tr[rc].sum;
}

void update(int p, int x, int k) {
    if (tr[p].l == x && tr[p].r == x) {
        tr[p].sum += k;
        return;
    }
    int mid = (tr[p].l + tr[p].r) >> 1;
    if (x <= mid)
        update(lc, x, k);
    else
        update(rc, x, k);
    tr[p].sum = tr[lc].sum + tr[rc].sum;
}

int query(int p, int x, int y) {
    if (x <= tr[p].l && tr[p].r <= y) {
        return tr[p].sum;
    }
    int mid = (tr[p].l + tr[p].r) >> 1;
    int sum = 0;
    if (x <= mid)
        sum += query(lc, x, y);
    if (y > mid)
        sum += query(rc, x, y);
    return sum;
}

void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> w[i];
    build(1, 1, n);
    while (m--) {
        int a, b, c;
        cin >> a >> b >> c;
        if (a == 1)
            update(1, b, c);
        else
            cout << query(1, b, c) << endl;
    }
}

signed main() {
    int _=1;
    while (_--)
        solve();
    return 0;
}

【模板】线段树 1

链接:https://www.luogu.com.cn/problem/P3372

题目描述

如题,已知一个数列,你需要进行下面两种操作:

  1. 将某区间每一个数加上 k k k
  2. 求出某区间每一个数的和。

输入格式

第一行包含两个整数 n , m n, m n,m,分别表示该数列数字的个数和操作的总个数。

第二行包含 n n n 个用空格分隔的整数,其中第 i i i 个数字表示数列第 i i i 项的初始值。

接下来 m m m 行每行包含 3 3 3 4 4 4 个整数,表示一个操作,具体如下:

  1. 1 x y k:将区间 [ x , y ] [x, y] [x,y] 内每个数加上 k k k
  2. 2 x y:输出区间 [ x , y ] [x, y] [x,y] 内每个数的和。

输出格式

输出包含若干行整数,即为所有操作 2 的结果。

样例 #1

样例输入 #1

5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4

样例输出 #1

11
8
20

提示

对于 30 % 30\% 30% 的数据: n ≤ 8 n \le 8 n8 m ≤ 10 m \le 10 m10
对于 70 % 70\% 70% 的数据: n ≤ 10 3 n \le {10}^3 n103 m ≤ 10 4 m \le {10}^4 m104
对于 100 % 100\% 100% 的数据: 1 ≤ n , m ≤ 10 5 1 \le n, m \le {10}^5 1n,m105

保证任意时刻数列中所有元素的绝对值之和 ≤ 10 18 \le {10}^{18} 1018

代码

#include <bits/stdc++.h>
#define int long long
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
#define debug(s, x) cout << "#debug:(" << s << ")=" << x << endl;
using namespace std;

#define lc p * 2
#define rc p * 2 + 1

const int N = 1e5 + 10;
int n, m;

struct tr {
    int l, r, sum, add;
} tr[N * 4];
int w[N];

void pushup(int p) {
    tr[p].sum = tr[lc].sum + tr[rc].sum;
}

void pushdown(int p) {
    if (tr[p].add) {
        tr[lc].sum += tr[p].add * (tr[lc].r - tr[lc].l + 1);
        tr[rc].sum += tr[p].add * (tr[rc].r - tr[rc].l + 1);
        tr[lc].add += tr[p].add;
        tr[rc].add += tr[p].add;
        tr[p].add = 0;
    }
}

void build(int p, int l, int r) {
    tr[p] = {l, r, w[l], 0};
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    build(lc, l, mid);
    build(rc, mid + 1, r);
    pushup(p);
}

void update(int p, int x, int y, int k) {
    if (x <= tr[p].l && tr[p].r <= y) {
        tr[p].sum += (tr[p].r - tr[p].l + 1) * k;
        tr[p].add += k;
        return;
    }
    pushdown(p);
    int mid = (tr[p].l + tr[p].r) >> 1;
    if (x <= mid)
        update(lc, x, y, k);
    if (y > mid)
        update(rc, x, y, k);
    pushup(p);
}

int query(int p, int x, int y) {
    if (x <= tr[p].l && tr[p].r <= y) {
        return tr[p].sum;
    }
    pushdown(p);
    int mid = (tr[p].l + tr[p].r) >> 1;
    int res = 0;
    if (x <= mid)
        res += query(lc, x, y);
    if (y > mid)
        res += query(rc, x, y);
    pushup(p);
    return res;
}

void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> w[i];
    build(1, 1, n);
    while (m--) {
        int op;
        cin >> op;
        if (op == 1) {
            int x, y, k;
            cin >> x >> y >> k;
            update(1, x, y, k);
        } else {
            int x, y;
            cin >> x >> y;
            cout << query(1, x, y) << endl;
        }
    }
}
signed main() {
    int _ = 1;
    while (_--)
        solve();
    return 0;
}

最大数

链接:https://www.acwing.com/problem/content/1277/

给定一个正整数数列 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,,an,每一个数都在 0 ∼ p − 1 0 \sim p-1 0p1 之间。

可以对这列数进行两种操作:

  1. 添加操作:向序列后添加一个数,序列长度变成 n + 1 n+1 n+1
  2. 询问操作:询问这个序列中最后 L L L 个数中最大的数是多少。

程序运行的最开始,整数序列为空。

一共要对整数序列进行 m m m 次操作。

写一个程序,读入操作的序列,并输出询问操作的答案。

输入格式

第一行有两个正整数 m , p m,p m,p,意义如题目描述;

接下来 m m m 行,每一行表示一个操作。

如果该行的内容是 Q L,则表示这个操作是询问序列中最后 L L L 个数的最大数是多少;

如果是 A t,则表示向序列后面加一个数,加入的数是 ( t + a )   m o d   p (t+a)\ mod\ p (t+a) mod p。其中, t t t 是输入的参数, a a a 是在这个添加操作之前最后一个询问操作的答案(如果之前没有询问操作,则 a = 0 a=0 a=0)。

第一个操作一定是添加操作。对于询问操作, L > 0 L>0 L>0 且不超过当前序列的长度。

输出格式

对于每一个询问操作,输出一行。该行只有一个数,即序列中最后 L L L 个数的最大数。

数据范围

1 ≤ m ≤ 2 × 1 0 5 1 \le m \le 2 \times 10^5 1m2×105,
1 ≤ p ≤ 2 × 1 0 9 1 \le p \le 2 \times 10^9 1p2×109,
0 ≤ t < p 0 \le t < p 0t<p

输入样例:

10 100
A 97
Q 1
Q 1
A 17
Q 2
A 63
Q 1
Q 1
Q 3
A 99

输出样例:

97
97
97
60
60
97

样例解释

最后的序列是 97 , 14 , 60 , 96 97,14,60,96 97,14,60,96

思路

因为一开始序列的长度不知道是多少,但是最多m个询问,最坏情况下数组长度就为m呗,初始化的时候就可以建立1,m的线段树

然后使用线段树维护区间的最大值,使用n记录此时数组的长度,每次添加操作,n就加1

代码

#include <bits/stdc++.h>
#define int long long
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
#define debug(s, x) cout << "#debug:(" << s << ")=" << x << endl;
using namespace std;

#define lc p << 1
#define rc p << 1 | 1

const int N = 2e5 + 10;

int n = 1, m, p, a;

struct node {
    int l, r, sum;
} tr[N * 4];

void pushdown(int p) {
    tr[p].sum = max(tr[lc].sum, tr[rc].sum);
}

void build(int p, int l, int r) {
    tr[p] = {l, r, 0};
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    build(lc, l, mid);
    build(rc, mid + 1, r);
}

void update(int p, int x, int k) {
    if (tr[p].l == x && tr[p].r == x) {
        tr[p].sum = k;
        return;
    }
    int mid = (tr[p].l + tr[p].r) >> 1;
    if (x <= mid)
        update(lc, x, k);
    else
        update(rc, x, k);
    pushdown(p);
}

int query(int p, int x, int y) {
    if (x <= tr[p].l && tr[p].r <= y) {
        return tr[p].sum;
    }
    int mid = (tr[p].l + tr[p].r) >> 1;
    int res = 0;
    if (x <= mid)
        res = max(res, query(lc, x, y));
    if (y > mid)
        res = max(res, query(rc, x, y));
    return res;
}

void solve() {
    cin >> m >> p;
    build(1, 1, m);
    while (m--) {
        char op;
        int x;
        cin >> op >> x;
        if (op == 'A') {
            update(1, n, (a + x) % p);
            n++;
        } else {
            a = query(1, n - x, n - 1);
            cout << a << endl;
        }
    }
}
signed main() {
    int _ = 1;
    while (_--)
        solve();
    return 0;
}

你能回答这些问题吗

链接:https://www.acwing.com/problem/content/description/246/

给定长度为 N N N 的数列 A A A,以及 M M M 条指令,每条指令可能是以下两种之一:

  1. 1 x y,查询区间 [ x , y ] [x,y] [x,y] 中的最大连续子段和,即 max ⁡ x ≤ l ≤ r ≤ y \max\limits_{x \le l \le r \le y} xlrymax{ ∑ i = l r A [ i ] \sum\limits^r_{i=l} A[i] i=lrA[i]}。
  2. 2 x y,把 A [ x ] A[x] A[x] 改成 y y y

对于每个查询指令,输出一个整数表示答案。

输入格式

第一行两个整数 N , M N,M N,M

第二行 N N N 个整数 A [ i ] A[i] A[i]

接下来 M M M 行每行 3 3 3 个整数 k , x , y k,x,y k,x,y k = 1 k=1 k=1 表示查询(此时如果 x > y x>y x>y,请交换 x , y x,y x,y), k = 2 k=2 k=2 表示修改。

输出格式

对于每个查询指令输出一个整数表示答案。

每个答案占一行。

数据范围

N ≤ 500000 , M ≤ 100000 N \le 500000, M \le 100000 N500000,M100000,
− 1000 ≤ A [ i ] ≤ 1000 -1000 \le A[i] \le 1000 1000A[i]1000

输入样例:

5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2

输出样例:

2
-1

思路

用线段树维护区间最大的连续子段和:

  • s u m sum sum记录区间 [ l , r ] [l,r] [l,r]的和
  • l m a x lmax lmax记录区间 [ l , r ] [l,r] [l,r]的从 l l l开始的最大连续子段和
  • r m a x rmax rmax记录区间 [ l , r ] [l,r] [l,r]的从 r r r开始的最大连续子段和
  • m a x max max记录区间 [ l , r ] [l,r] [l,r]的最大连续子段和

在更新父节点的这些数据时,有:

  • t r [ p ] . s u m = t r [ l c ] . s u m + t r [ r c ] . s u m ; tr[p].sum = tr[lc].sum + tr[rc].sum; tr[p].sum=tr[lc].sum+tr[rc].sum;

父节点的区间和就是两个子节点的区间和之和

  • t r [ p ] . l m a x = m a x ( t r [ l c ] . l m a x , t r [ l c ] . s u m + t r [ r c ] . l m a x ) ; tr[p].lmax = max(tr[lc].lmax, tr[lc].sum + tr[rc].lmax); tr[p].lmax=max(tr[lc].lmax,tr[lc].sum+tr[rc].lmax);

父节点从左开始的最大连续子段和为 max(左儿子从左开始的最大连续字段和,左孩子的区间和+右儿子从左开始的最大连续子段和)

  • t r [ p ] . r m a x = m a x ( t r [ r c ] . r m a x , t r [ r c ] . s u m + t r [ l c ] . r m a x ) ; tr[p].rmax = max(tr[rc].rmax, tr[rc].sum + tr[lc].rmax); tr[p].rmax=max(tr[rc].rmax,tr[rc].sum+tr[lc].rmax);
  • t r [ p ] . m a x = m a x ( m a x ( t r [ l c ] . m a x , t r [ r c ] . m a x ) , t r [ l c ] . r m a x + t r [ r c ] . l m a x ) ; tr[p].max = max(max(tr[lc].max, tr[rc].max), tr[lc].rmax + tr[rc].lmax); tr[p].max=max(max(tr[lc].max,tr[rc].max),tr[lc].rmax+tr[rc].lmax);

父节点的区间最大连续字段和为 左儿子的右连续区间和+右儿子的左连续区间和 以及左右儿子各自最大连续区间和之一。

代码

#include <bits/stdc++.h>
#define int long long
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
#define debug(s, x) cout << "#debug:(" << s << ")=" << x << endl;
using namespace std;
#define lc p << 1
#define rc p << 1 | 1

const int N = 5e5 + 10;
int n, m;
int w[N];
struct node {
    int l, r, sum, lmax, rmax, max;
} tr[N * 4];

void pushdown(int p) {
    tr[p].sum = tr[lc].sum + tr[rc].sum;
    tr[p].lmax = max(tr[lc].lmax, tr[lc].sum + tr[rc].lmax);
    tr[p].rmax = max(tr[rc].rmax, tr[rc].sum + tr[lc].rmax);
    tr[p].max = max(max(tr[lc].max, tr[rc].max), tr[lc].rmax + tr[rc].lmax);
}

void build(int p, int l, int r) {
    tr[p] = {l, r, w[l], w[l], w[l], w[l]};
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    build(lc, l, mid);
    build(rc, mid + 1, r);
    pushdown(p);
}

void update(int p, int x, int k) {
    if (tr[p].l == x && tr[p].r == x) {
        tr[p] = {x, x, k, k, k, k};
        return;
    }
    int mid = (tr[p].l + tr[p].r) >> 1;
    if (x <= mid)
        update(lc, x, k);
    else
        update(rc, x, k);
    pushdown(p);
}

node query(int p, int x, int y) {
    if (x <= tr[p].l && tr[p].r <= y) {
        return tr[p];
    }
    int mid = (tr[p].l + tr[p].r) >> 1;
    if (y <= mid)
        return query(lc, x, y);
    if (x > mid)
        return query(rc, x, y);
    node left = query(lc, x, y);
    node right = query(rc, x, y);
    node t;
    t.sum = left.sum + right.sum;
    t.lmax = max(left.lmax, left.sum + right.lmax);
    t.rmax = max(right.rmax, right.sum + left.rmax);
    t.max = max(max(left.max, right.max), right.lmax + left.rmax);
    return t;
}

void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> w[i];
    build(1, 1, n);
    int op, x, y;
    while (m--) {
        cin >> op >> x >> y;
        if (op == 1) {
            if (x > y)
                swap(x, y);
            cout << query(1, x, y).max << endl;
        } else
            update(1, x, y);
    }
}
signed main() {
    int _ = 1;
    while (_--)
        solve();
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/642835.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#多线程Task常见问题(二)

1 多线程临时变量 2 线程安全和锁lock 3 线程安全策略总结 线程安全和锁lock 线程安全问题&#xff1a;一段程序逻辑在单线程中执行和多线程中执行&#xff0c;结果一致说明线程是安全的&#xff1b;如果结果不同说明线程不安全。 同样先看一个例子&#xff1a;分别用主线程…

唯品会宕机惨案,损失超亿元!故障来时如何迅速应对?

01 事件回顾 对于IT工程师来说&#xff0c;宕机并非新鲜话题&#xff0c;经历过一次服务器宕机&#xff0c;职业生涯才“完整”。但如果事故超过 12 小时&#xff0c;或许会直接造成职业生涯“宕机”。 3月29日发生的突发事件&#xff0c;#唯品会App崩了 冲上热搜&#xff0…

最全整理,完整一套WEB/APP/接口测试测试流程,全面覆盖...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 web测试流程 需求…

Java --- springboot3整合redis

目录​​​​​​​ 一、整合redis 1.1、导入pom依赖 1.2、修改springboot配置文件 1.3、代码测试 二、测试访问redis五大常用数据类型 三、自动配置原理 四、定制化 4.1、解决redis存储序列化乱码问题 4.2、redis客户端使用jedis 一、整合redis 1.1、导入pom依赖 …

【考试】2023年5月软件设计师考试感受

前言❤️ 由于考试地点距离住的地方很远&#xff0c;一个南面一个北面&#xff0c;所以BZ选择了提前一天去到考试地点附近&#xff0c;住在考点附近。吃了晚饭后。到住的地方大概9点多&#xff0c;洗漱完&#xff0c;10点左右开始考前过知识点&#xff0c;复习到凌晨3点左右。…

改进的粒子滤波算法及其应用研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【博客660】prometheus默认5min的lookback机制带来查询的影响

prometheus默认5min的lookback机制带来查询的影响 1、prometheus staleness机制 我发过的&#xff1a;【博客616】prometheus staleness对PromQL查询的影响 官方staleness解析 相关文章&#xff1a;do-prometheus-metrics-have-some-sort-of-freshness-lifetime 相关issue…

全面解析数据治理

摘要 数据治理并不是一种简单的操作行为&#xff0c;而是对数据资产管理行使权力和控制的活动集合&#xff0c;是一种管理和保护数据的方法&#xff0c;是确保准确性、完整性、安全性、可靠性和一致性的关键。 通过数据治理&#xff0c;企业可以更好地掌握现有数据&#xff0…

C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

文章目录 前言&#x1f31f;一、为什么存在动态内存分配&#x1f31f;二、动态内存函数的介绍&#x1f30f;2.1.malloc函数free函数&#x1f30f;2.2.calloc函数free函数&#x1f30f;2.3.realloc函数 &#x1f31f;三、常见的动态内存错误&#x1f30f;3.1.对NULL指针的解引用…

SQL(--修改中--)

目录 一、基本介绍 二、常用函数 集合函数 字符串函数 MYSQL的日期和时间函数 SQL重要的内建日期函数 MYSQL重要的内建日期函数 条件判断函数 三、操作 单表查询 多表查询 使用正则表达式查询 添加&#xff1a; 修改&#xff1a; 删除&#xff1a; 四、…

Linux系统实现虚拟内存教程

Linux系统实现虚拟内存有两种方法&#xff1a;交换分区&#xff08;swap分区&#xff09;和交换文件&#xff0c; 一、交换文件 查看内存&#xff1a;free -m , -m是显示单位为MB&#xff0c;-g单位GB free -g 创建一个文件&#xff1a;touch命令用于修改…

【2023电工杯】A题 电采暖负荷参与电力系统功率调节的技术经济分析 30页论文及python代码

【2023电工杯】A题 电采暖负荷参与电力系统功率调节的技术经济分析 30页论文及python代码 1 题目 A题:电采暖负荷参与电力系统功率调节的技术经济分析 建设以新能源为主体的新型电力系统是应对全球气候变化挑战的重要举措。高比例新能源接入导致电力系统调节能力稀缺&#x…

电厂人员定位管理系统,厂区人员及车辆轨迹可循

随着科技的不断发展&#xff0c;室内定位技术已经逐渐成为电厂管理中不可或缺的一部分。在传统的变电站管理中&#xff0c;由于缺乏有效的定位技术&#xff0c;很难对设备、人员和物资进行精确的管理&#xff0c;导致了效率低下、成本高昂的问题。而现在&#xff0c;通过引入室…

企业必须知道:数字化官网已成为新发展格局

​如今我们生活在一个数据驱动发展的时代&#xff0c;不能顺应时代发展进步的企业就会落后和淘汰。一个新技术时代应运而生&#xff0c;一个数据主导的数字企业时代也必将应声而至。 社交媒体、移动设备、物联网和大数据引发的数字化趋势不仅改变了人们的生活方式而且要求企业…

工厂模式(四)

过气的&#xff0c;终究是过气了 上一章简单介绍了单例模式(三), 如果没有看过,请观看上一章 一. 工厂模式 引用 菜鸟教程里面的单例模式介绍: https://www.runoob.com/design-pattern/factory-pattern.html 工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常…

输电线路可视化监拍装置硬件解决方案

老旧输电线路可视化监控装置 随着我国人口的增长&#xff0c;电力设施的规模也变得越发庞大&#xff0c;人工运检的负担也越来越沉重&#xff0c;而且巡检的时效性也是痛点&#xff0c;于是电网提出智慧可视化管理通道运检的方案&#xff0c;线路在线监测装置成为其基础&#x…

前端开发环境部署问题(高级程序员必备)

很多开发者到了一家新公司&#xff0c;公司发了一台新电脑&#xff0c;对环境安装比较困惑。今天带大家还原&#xff0c;拿到公司电脑&#xff0c;如何安装你需要的各种环境。 一、node安装 官网下载地址&#xff1a; http://nodejs.cn/download/ 根据自己需要下载对应的版…

电脑多久重装一次系统比较好

在长时间使用电脑后&#xff0c;一些用户可能会考虑重装系统来提升性能和稳定性。然而&#xff0c;电脑重装系统的频率是一个有争议的问题。本文将探讨电脑重装系统的最佳频率&#xff0c;以帮助您做出明智的决策。 工具/原料&#xff1a; 系统版本&#xff1a;win7旗舰版 品…

如何使用Leangoo领歌敏捷工具管理Sprint Backlog

什么是Sprint Backlog&#xff1f; Sprint Backlog是Scrum的主要工件之一。在Scrum中&#xff0c;团队按照迭代的方式工作&#xff0c;每个迭代称为一个Sprint。在Sprint开始之前&#xff0c;PO会准备好产品Backlog&#xff0c;准备好的产品Backlog应该是经过梳理、估算和优先…

编译原理期末速成-自上而下分析、消除文法的左递归问题

文章目录 自上而下分析面临的问题文法左递归问题回溯问题 构造不带回溯的自上而下分析算法消除文法的左递归 自上而下分析 自上而下就是从文法的开始符号出发&#xff0c;向下推导&#xff0c;推出句子。 面临的问题 文法左递归问题 左递归在语法分析过程中可能会导致无限循环…