算法提高-线段树

news2024/12/23 23:22:16

线段树

  • 线段树和树状数组
  • 线段树的五个操作
  • 单点修改(不需要懒标记)
    • 要求的答案就是我们要维护的属性,不需要维护其他的属性帮助我们获得答案
    • 要求的答案还需要其他属性去维护
  • 区间修改(需要懒标记,pushdown)
    • 有关于啥时候要pushdown(清除懒标记)

1.19
线段树维护的是区间上的属性:
query的本质就是将要查询的区间[l,r]不断切割,最后由我们预处理好的区间组成,答案也从这些预处理的区间中收集。

线段树和树状数组

线段树相当于大砍刀战斗切菜什么都可以,树状数组相当于一个手术刀,很精细效率很高。
线段树:

  • 单点修改,单点查询
  • 区间修改,区间查询(加上懒标记后)
  • 前两点相互组合,可以实现对区间的任意修改和查询

树状数组:

  • 区间求和,单点修改(树状数组的本质–前缀和以及单点修改)
  • 区间修改,单点求和(维护差分数组)
  • 区间修改,区间求和(维护两个树状数组,一个差分数组,一个ib[i]数组)
  • 树状数组这些变式都是在树状数组的本质上延伸的,其实他本质就是结合了数组单点修改和前缀和的一个数据结构。

tip:树状数组本质就是单点修改和区间求和,其他的额外操作都是我们自己设计的(差分实现区间修改 或者 推公式结合差分实现区间求和)而线段树的操作都是这个数据结构自己自带的。

线段树的五个操作

pushdown、pushup、modify、query、build

单点修改(不需要懒标记)

要求的答案就是我们要维护的属性,不需要维护其他的属性帮助我们获得答案

1275. 最大数
这题很奇怪,用cin >> m >> p不行,必须是scanf(“%d%d”, &m,&p);但是我打印了明明mp都被正确赋值了

#include <iostream>

using namespace std;
typedef pair<int, int> pii;
const int N = 2e5 + 10;

struct Node{
    int l, r;
    int v;
}tr[N * 4];

void pushup(int u) 由子节点的信息,来计算父节点的信息
{
    tr[u].v = max(tr[u << 1].v, tr[u << 1|1].v);
}
void build(int u, int l, int r)
{
    tr[u] = {l, r};
    if (l == r) return;
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1|1, mid + 1, r);//用堆的方式储存线段树
    pushup(u);
}

void modify(int u, int x, int v)
{
    if (tr[u].l == x && tr[u].r == x) tr[u].v = v;
    else 
    {
        int mid = tr[u].l + tr[u].r >> 1;
        if (x <= mid) modify(u << 1, x, v);
        else modify(u << 1|1, x, v);
        pushup(u);
    }
}
int query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r) return tr[u].v;
    int mid = tr[u].l + tr[u].r >> 1;
    int v = 0;
    if (mid >= l) v = query(u << 1, l, r);
    if (mid < r) v = max(v, query(u << 1|1, l, r));//只判断mid < r 而不是<= 是因为(l ,mid)就是左区间,(mid+1, r)就是右区间
    return v; 
}
void solve()
{  
    
    int m, p;
    // cin >> m >> p;   
    scanf("%d%d", &m, &p);
    // cout << "mp :" << m << p << endl;
    build(1, 1, m);
    
    char op[2];
    int last = 0, n = 0;//n表示当前节点的数量
    int x;
    while (m -- )
    {
        scanf("%s%d", op, &x);
        if (*op == 'A')
        {
            modify(1, n + 1, (x + (long long)last) % p);
            n++;
        }
        else 
        {
            last = query(1, n - x + 1, n);
            
            cout << last << endl;
        }
    }    
}
int32_t main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T = 1;
    // cin >> T;
    while (T --) solve();
    return 0;
}

要求的答案还需要其他属性去维护

AcWing 245. 你能回答这些问题吗

#include <iostream>

using namespace std;
typedef pair<int, int> pii;
const int N = 5e5 + 10;
// 5 3
// 1 2 -3 4 5
// 1 2 3
// 2 2 -1
// 1 3 2
int w[N];
struct Node
{
    int l, r;
    int sum, lmax, rmax, tmax;
}tr[N * 4];

void pushup(Node &u, Node &left, Node &right)
{
    u.sum = left.sum + right.sum;
    u.lmax = max(left.lmax, left.sum + right.lmax);
    u.rmax = max(right.rmax, left.rmax + right.sum);
    u.tmax = max(max(left.tmax, right.tmax), left.rmax + right.lmax);
}

void pushup(int u)
{
    pushup(tr[u], tr[u << 1], tr[u << 1|1]);
}

void build(int u, int l, int r)
{
    if (l == r) tr[u] = {l, r, w[r], w[r], w[r], w[r]};
    else 
    {
        tr[u] = {l, r};
        int mid = l + r >> 1;
        build(u << 1, l, mid); build(u << 1|1, mid + 1, r);
        pushup(u);
    }
    int mid = l + r >> 1;
}

Node query(int u, int l, int r)//query的本质就是将[l,r]不断切割,最后由我们预处理好的区间组成,答案也从这些预处理的区间中收集
{
    if (tr[u].l >= l && tr[u].r <= r) return tr[u];

    int mid = tr[u].l + tr[u].r >> 1;
    if (r <= mid) return query(u << 1, l, r);//结果需要的区间只在左半边
    else if (l > mid) return query(u << 1|1, l, r);//结果需要的区间只在右半边
    else //结果的区间既在左半边也在右半边
    {
        auto left = query(u << 1, l, r);
        auto right = query(u << 1|1, l, r);
        Node res;
        pushup(res, left, right);//将两个区间查找到的答案收集给res节点
        return res;
    }
}

void modify(int u, int x, int v)
{
    if (tr[u].l == x && tr[u].r == x) tr[u] = {x, x, v, v, v, v};
    else 
    {
        int mid = tr[u].l + tr[u].r >> 1;
        if (mid >= x) modify(u << 1, x, v);
        else modify(u << 1|1, x, v);
        pushup(u);
    }
}

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

    int k, x, y;
    while (m -- )
    {
        scanf("%d%d%d", &k, &x, &y);
        if (k == 1)
        {
            if (x > y) swap(x, y);
            printf("%d\n", query(1, x, y).tmax);
        }
        else modify(1, x, y);
    }
}
int32_t main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T = 1;
    // cin >> T;
    while (T --) solve();
    return 0;
}

区间修改(需要懒标记,pushdown)

有关于啥时候要pushdown(清除懒标记)

在这里插入图片描述
在这里插入图片描述

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef pair<int, int> pii;
const int N = 1e5 + 10;
// 10 5
// 1 2 3 4 5 6 7 8 9 10
// Q 4 4
// Q 1 10
// Q 2 4
// C 3 6 3
// Q 2 4 
int n, m;
typedef long long LL;
struct Node{
    int l, r;
    LL sum, add;
}tr[N * 4];
int w[N];



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

void build(int u, int l, int r)
{
    if (l == r) tr[u] = {l, r, w[r], 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);//建完左右子树,也要补充当前节点的信息(sum,add默认为0)
    }
}
void pushdown(int u)
{
    auto &root = tr[u], &left = tr[u << 1], &right = tr[u << 1|1];
    if (root.add != 0)
    {
        left.add += root.add, right.add += root.add;
        left.sum += (left.r - left.l + 1) * root.add;
        right.sum += (right.r - right.l + 1) * root.add;
        root.add = 0;
    }
}
LL query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
    else
    {
        LL res = 0;
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) res = query(u << 1, l , r);
        if (r > mid) res += query(u << 1|1, l, r);
        pushup(u);
        return res;
    }
}

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 + 1) * d;
        tr[u].add += d;
    }
    else 
    {
        int mid = tr[u].l + tr[u].r >> 1;
        pushdown(u);//modify子区间后也需要更新父区间,也就是pushup,但是pushup前必须保证儿子区间是正确的值,因此要pushdown
        if (l <= mid) modify(u << 1, l, r, d);
        if (r > mid) modify(u << 1|1, l, r, d);
        pushup(u);//子节点返回信息给父节点的时候子节点自身的状态必须是正确的,
                 //因此要先清除子节点上面的懒标记,保证子节点自身的sum值是正确的
    }
}

void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i) cin >> w[i];  
    build(1, 1, n);

    char op[2];
    while (m -- )
    {
        cin >> op;
        int l, r, d;
        if (*op == 'Q')
        {
            cin >> l >> r;
            cout << query(1, l, r) << endl;
        }
        else 
        {
            cin >> l >> r >> d;
            modify(1, l, r, d);
        }
    }
}
int32_t main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T = 1;
    // cin >> T;
    while (T --) solve();
    return 0;
}

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

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

相关文章

小爱同学今日起开启邀请测试, 小米Al 大模型团队整装待发

在小米雷军年度演讲中&#xff0c;小米宣布未来将在技术研发上投入超过200亿元人民币&#xff0c;并预计在2023年达到这一目标。除此之外&#xff0c;雷军还强调了5G技术在小米发展中的重要性&#xff0c;称其为必要标准&#xff0c;并预测小米将进入世界前十的位置。 雷军还透…

配置 yum/dnf 置您的系统以使用默认存储库

题目 给系统配置默认存储库&#xff0c;要求如下&#xff1a; YUM 的 两 个 存 储 库 的 地 址 分 别 是 &#xff1a; ftp://host.domain8.rhce.cc/dvd/BaseOS ftp://host.domain8.rhce.cc/dvd/AppStream vim /etc/yum.repos.d/redhat.repo [base] namebase baseurlftp:/…

釉面陶瓷器皿SOR/2016-175标准上架亚马逊加拿大站

亲爱的釉面陶瓷器皿和玻璃器皿制造商和卖家&#xff0c;亚马逊加拿大站将执行SOR/2016-175法规。这是一份新的法规&#xff0c;规定了含有铅和镉的釉面陶瓷器和玻璃器皿需要满足的要求。让我们一起来看一看&#xff0c;为什么要实行SOR/2016-175法规&#xff1f;这是一个保护消…

Unity游戏源码分享-中国象棋Unity5.6版本

Unity游戏源码分享-中国象棋Unity5.6版本 项目地址&#xff1a; https://download.csdn.net/download/Highning0007/88215699

linux系统服务学习(一)Linux高级命令扩展

文章目录 Linux高级命令&#xff08;扩展&#xff09;一、find命令1、find命令作用2、基本语法3、*星号通配符4、根据文件修改时间搜索文件☆ 聊一下Windows中的文件时间概念&#xff1f;☆ 使用stat命令获取文件的最后修改时间☆ 创建文件时设置修改时间以及修改文件的修改时间…

母牛的故事

一、题目 有一头母牛&#xff0c;它每年年初生一头小母牛。每头小母牛从第四个年头开始&#xff0c;每年年初也生一头小母牛。请编程实现在第n年的时候&#xff0c;共有多少头母牛&#xff1f; Input 输入数据由多个测试实例组成&#xff0c;每个测试实例占一行&#xff0c;包…

11 个 Python 编码习惯

让你成为糟糕程序员的 11 个 Python 编码习惯 简介 Python 因其简洁性和可读性而备受推崇&#xff0c;但即使是最有经验的程序员也可能会陷入影响代码质量的习惯中。 在本博客中&#xff0c;我们将探讨 10 种常见的编码习惯&#xff0c;它们会降低您作为 Python 程序员的效率。…

深入探析设计模式:工厂模式的三种姿态

深入探析设计模式&#xff1a;工厂模式的三种姿态 1. 简单工厂模式1.1 概念1.2 案例1.3 优缺点 2. 抽象工厂模式2.1 概念2.2 案例&#xff1a;跨品牌手机生产2.3 优缺点 3. 超级工厂模式3.1 概念3.2 案例&#xff1a;动物园游览3.3 优缺点 4. 总结 欢迎阅读本文&#xff0c;今天…

windows10和linux18.04中配置mmhuman3d

分类&#xff1a;动作捕捉 github地址&#xff1a;https://github.com/open-mmlab/mmhuman3d 所需环境&#xff1a; Windows10&#xff0c;CUDA11.6&#xff0c;conda 4.13.0&#xff0c;Visual Studio 2017&#xff1b; Ubuntu18.04&#xff0c;conda22.9.0&#xff0c;CUDA11…

人工智能能够通过所有[创造力测试]

沃顿商学院教授Ethan Mollick emollick 分享了三篇新的实验性论文&#xff0c;证明了AI在实际情境中的创造力。 https://www.oneusefulthing.org/p/automating-creativity “GPT-4 现在在替代用途测试中击败了 91% 的人类&#xff0c;在托伦斯创造性思维测试中击败了 99% 的人类…

每天一道leetcode:1466. 重新规划路线(图论中等广度优先遍历)

今日份题目&#xff1a; n 座城市&#xff0c;从 0 到 n-1 编号&#xff0c;其间共有 n-1 条路线。因此&#xff0c;要想在两座不同城市之间旅行只有唯一一条路线可供选择&#xff08;路线网形成一颗树&#xff09;。去年&#xff0c;交通运输部决定重新规划路线&#xff0c;以…

网络安全专业术语英文缩写对照表

因在阅读文献过程中经常遇到各种专业缩写&#xff0c;所以把各种缩写总结了一下。 因能力有限&#xff0c;错误在所难免&#xff0c;欢迎进行纠错与补充&#xff1a;https://github.com/piaolin/CSAbbr 渗透相关 缩写全称解释备注XSSCross Site Script Attack跨站脚本攻击为…

前端食堂技术周刊第 94 期:TS 5.2 RC、从零实现 RSC、Redux 迁移至 ESM 之旅、HTML 满汉全席

美味值&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f; 口味&#xff1a;葡茉美式 食堂技术周刊仓库地址&#xff1a;https://github.com/Geekhyt/weekly 大家好&#xff0c;我是童欧巴。欢迎来到前端食堂技术周刊&#xff0c;我们先来看下…

揭秘国产操作系统的黄金测试利器:探索开源测试工具的神秘世界

揭秘国产操作系统的黄金测试利器&#xff1a;探索开源测试工具的神秘世界 文章目录 1.前言2.国产操作系统现状的深度解析3.国产操作系统的质量保障神器(开源测试工具)4.开源测试工具的重要性5.国产操作系统如何利用开源测试工具进行黄金测试6.国产操作系统的开源测试工具整合方…

python安装第三方包时报错:...\lib\site-packages\pip\_vendor\urllib3\response.py...

安装redis第三方包&#xff1a; pip install redis报错现象&#xff1a; 解决方法&#xff1a;使用以下命令可成功安装 pip install redis -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

IT运维:使用数据分析平台监控深信服防火墙

概述 深信服防火墙自身监控可以满足绝大部分需求&#xff0c;比如哪个应用占了最大带宽&#xff0c;哪个用户访问了哪些网站&#xff1f;这里我们为什么使用鸿鹄呢&#xff1f;因为我们要的是数据的处理和分析&#xff0c;比如某个用户在某个事件都做了哪些行为&#xff0c;这个…

OpenCV图像处理——轮廓检测

目录 图像的轮廓查找轮廓绘制轮廓 轮廓的特征轮廓面积轮廓周长轮廓近似凸包边界矩形最小外接圆椭圆拟合直线拟合 图像的矩特征矩的概念图像中的矩特征 图像的轮廓 查找轮廓 binary,contours,hierarchycv.findContours(img,mode,method)绘制轮廓 cv.drawContours(img,coutours…

找不到mfc140u.dll怎么办?mfc140u.dll丢失怎样修复?简单三招搞定

最近我遇到了一个问题&#xff0c;发现我的电脑上出现了mfc140u.dll文件丢失的错误提示。这个错误导致一些应用程序无法正常运行&#xff0c;让我感到非常困扰。经过一番研究和尝试&#xff0c;我终于成功修复了这个问题&#xff0c;并从中总结出了一些心得。 mfc140u.dll丢失原…

Claude2 Api接入方案

一&#xff0c;实现目标 接入钉钉机器人支持群聊和私聊 网上看了很多方案&#xff0c;因为Claude的api申请难度非常大&#xff0c;大部分都是说使用Slack&#xff0c;但是Slack只能免费使用一个月。作为一个完美主义怎么可能允许这样的事情发生。何如处理&#xff0c;抓网页。…

基于Redis实现全局唯一Id

微信公众号访问地址&#xff1a;基于Redis实现全局唯一Id 推荐文章&#xff1a; 1、使用原生Redis命令实现分布式锁 ​ 2、为什么引入Redisson分布式锁&#xff1f; 3、SpringBoot整合多数据源&#xff0c;并支持动态新增与切换&#xff08;详细教程&#xff09; 4、Sprin…