2025/5/2集训

1.线段树

1.1.引入

当一些比较难的区间问题出现时,我们需要线段树.

1.2.概念

线段树 约等于 二叉树
共有\(\log_2(n)\)层,\(2^{(depth+1)}\)个节点(\(depth\)是深度)

1.3.操作

1.3.1.计算信息

合并左儿子和右儿子的信息(所有线段树必备)(叶子节点直接访问就行)

1.3.2.合并(区间加法)

往上一直加就行(顾名思义)

1.4.实现

1.4.1.建树

#include <bits/stdc++.h>
using namespace std;
//线段树 
const int maxn = 100010;
int n, m, a[maxn];
struct node{//一个线段树节点
    int sum;//区间和 
    int size;//区间长度 
    int add;//这段区间被整体加了多少
    node(){
        sum = size = add = 0;
    }
    void init(int v){
        sum = v;
        size = 1;
    }
}z[maxn<<2]; 
#define root 1,n,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
node operator+(const node &l, const node &r){
    node res;
    res.sum = l.sum+r.sum;
    res.size = l.size+r.size;
    return res;
}
void color(int l, int r, int rt, int v){//给l,r,rt节点打一个+v的懒标记
    z[rt].add += v;
    z[rt].sum += z[rt].size*v;
}
void push_col(int l, int r, int rt){//标记下放,把标记告诉儿子 
    if (z[rt].add == 0) return;//没标记,不需要下放 (可以不要,但会变慢)
    int m = (l+r)>>1;//有标记,需要下放
    color(lson, z[rt].add);
    color(rson, z[rt].add);
    z[rt].add = 0;//下放完了,直接清空 
}
void build(int l, int r, int rt){//建树 
    //用3个数字描述线段树:编号为rt的节点对应区间为l~r
    if (l == r){//叶子节点 
        z[rt].init(a[l]);
        return;
    } 
    int m = (l+r)>>1;
    build(lson);
    build(rson);
    //开始合并 
    z[rt] = z[rt<<1]+z[rt<<1|1];
}
node query(
    int l, int r, int rt, //l,r,rt同build
    int nowl, int nowr//nowl和nowr表示当前询问的区间 
){
    if (nowl <= l && r <= nowr) return z[rt];
    push_col(l, r, rt);
    int m = (l+r)>>1;
    if (nowl <= m){
        if (m < nowr) return query(lson, nowl, nowr)+query(rson, nowl, nowr);
        else return query(lson, nowl, nowr);
    }
    else return query(rson, nowl, nowr);
}
void modify(int l, int r, int rt, int nowl, int nowr, int v){
    //把nowl到nowr全部+=v
    if (nowl <= l && r <= nowr){//当前线段树节点被修改区间整体包含
        color(l, r, rt, v);
        return; 
    } 
    push_col(l, r, rt);
    int m = (l+r)>>1;
    if (nowl <= m) modify(lson, nowl, nowr, v);
    if (m < nowr) modify(rson, nowl, nowr, v);
    z[rt] = z[rt<<1]+z[rt<<1|1];
}
int main(){
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    build(root);
    cin >> m;
    for (int i = 1; i <= m; i++){
        int opt;
        cin >> opt;
        if (opt == 1){//询问
            int l, r;
            cin >> l >> r; 
            node answ = query(root, l, r);
            cout << answ.sum << '\n';
        }
        else if (opt == 2){//修改(把l~r全+=v) 
            int l, r, v;
            cin >> l >> r >> v;
            modify(root, l, r, v);
        }
    }
    return 0;
}

posted on 2025-05-02 10:50  穆昕雨  阅读(7)  评论(0)    收藏  举报

导航