首页 > 其他分享 >线段树的板子题

线段树的板子题

时间:2024-04-13 22:14:56浏览次数:21  
标签:int LL tr 板子 sum 区间 线段

线段树支持单点修改,单点查询,区间修改,区间查询
pushup:子节点更新父节点
pushdown:把懒标记向下传
build:初始化一颗树
modify:修改一个区间
query:查询一个区间

线段树的完整代码

AcWing 243. 一个简单的整数问题2 链接:https://www.acwing.com/problem/content/244/

#include <cstdio>
const int N = 100010;
typedef long long LL;

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

void pushup(int u) {
    tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}

void pushdown(int u) {
    Node &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
    if (root.add) {
        left.add += root.add, left.sum += (left.r - left.l + 1ll) * root.add;
        right.add += root.add, right.sum += (right.r - right.l + 1ll) * root.add;
        root.add = 0;
    }
}

void build(int u, int l, int r) {
    if (l == r) {
        tr[u] = {l, r, w[l], 0};
    } else {
        tr[u] = {l, r};
        int mid = l + r >> 1;
        build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}
void modify(int u, int l, int r, int d) {
    if (tr[u].l >= l && tr[u].r <= r) {
        tr[u].sum += (tr[u].r - tr[u].l + 1ll) * d;
        tr[u].add += d;
    } else {
        // 此时是需要分裂修改了,需要pushdown一下
        pushdown(u);
        int mid = tr[u].r + tr[u].l >> 1;
        if (l <= mid)
            modify(u << 1, l, r, d);
        if (r > mid)
            modify(u << 1 | 1, l, r, d);
        pushup(u);
    }
}

LL query(int u, int l, int r) {
    if (tr[u].l >= l && tr[u].r <= r)
        return tr[u].sum;

    // 查询了,也是分裂查询,先pushdown一下
    pushdown(u);

    int mid = tr[u].l + tr[u].r >> 1;
    LL sum = 0;
    if (l <= mid)
        sum += query(u << 1, l, r);
    if (r > mid)
        sum += query(u << 1 | 1, l, r);
    return sum;
}

int main() {

    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &w[i]);

    build(1, 1, n);

    char op[2];
    int l, r, d;
    while (m--) {
        scanf("%s", op);
        if (op[0] == 'Q') {
            scanf("%d%d", &l, &r);
            printf("%lld\n", query(1, l, r));
        } else {
            scanf("%d%d%d", &l, &r, &d);
            modify(1, l, r, d);
        }
    }
    return 0;
}

标签:int,LL,tr,板子,sum,区间,线段
From: https://www.cnblogs.com/zdwzdwzdw/p/18133457

相关文章

  • 主席树的板子题
    题解方法1.可持久化线段树(主席树),代码有详细注释做法:先把值离散化在数值上建立线段树,维护每个数值区间中一共有多少个数问题1:如何求整体第K小数?答:二分,如果0~mid中有cnt数,cnt>=k,递归左边,如果cnt<k,递归右边,找k−cnt小的数。时间复杂的logn问题2:求【1,R】这个区间的第K......
  • JAVA 板子
    代码片段1importjava.io.BufferedReader;importjava.io.BufferedWriter;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.OutputStreamWriter;importjava.io.PrintWriter;importjava.io.StreamTokenizer;publicclassMain{stati......
  • 【学习笔记】线段树(待补)
    零、写在前面的话我发现学习笔记是真的有必要的。很多比赛甚至做题的时候,学过的算法就出现在题目里面,然而我却忘记了之前对这个算法的深入理解,甚至忘了这个算法怎么打,更甚者,看不出来这个题目可以使用这种算法解决。为了防止这种情况再度出现,我决定对自己的任何学过的算法写笔记,......
  • Splay 板子
    普通:bool_Start;#include<bits/stdc++.h>usingnamespacestd;#defineilinline#defineTptemplate<typenameT>#defineTstemplate<typenameT,typename..._T>Tpilvoidread(T&x){ x=0;boolf=0;charc=getchar(); for(;!isdigit(c)......
  • 李超线段树
    李超线段树一般用来解决线段交集凸包问题:加入一个一次函数,定义域为\([l,r]\)给定\(k\),求定义域包含\(k\)的所有一次函数中,在\(x=k\)处取值最大的那个,如果有多个函数取值相同,选编号最小的看到区间修改,我们按照线段树解决区间问题的常见方法,给每个节点一个懒标记,每个节点......
  • [DS 小计] 线段树合并
    引入现在你有很多棵二叉树。二叉树的节点总和是\(n\)。现在,你要把它们合并。怎么做呢?实际上,写的好是可以\(O(n)\)完成的。前置题目1给出\(2\)棵二叉树,合并两棵二叉树。怎么做呢?很容易的暴力,遍历每个点,合并即可。合并我们进行以下分类讨论:如果现在\(u\),\(v......
  • 字符串哈希板子
    #include<iostream>#include<cstring>#defineMAX_SIZE100usingnamespacestd;classStringHash{public:intsize;char*array;char*array_forward;unsignedlonglong*pre_base;unsignedlonglong*hash_array;uns......
  • [DS 小计] 线段树分治
    很简单的一个小trick。就看能不能想出来。思考我们学过CDQ分治。CDQ分治的思想是把时间切割,询问截断点后面的问题,预处理截断点前面的贡献。这是把问题和修改放在一起的。那么,假设修改很难撤销怎么办?这时候就可以用线段树分治做到只增不删。有点类似回滚莫队。算法直......
  • 每日一题 第六十五期 洛谷 线段树1
    【模板】线段树1题目描述如题,已知一个数列,你需要进行下面两种操作:将某区间每一个数加上kkk。求出某区间每一个数的和。输入格式第一行包含两个整数......
  • [DS 小计] 李超线段树
    前言大家好啊,今天讲的是LCT(李超Tree)(bushi错了错了。这两不是一个东西。概念李超树能干什么。插入一条直线/线段单点查询当前点的峰值(最大最小均可)你会说:OI中有什么是和斜率相关的吗?有,那就是斜率优化。关于斜率优化可以看这个。你会说:你说的对,静态的dp......