线段树模板+例题

线段树是一种二叉搜索数,一般用来实现动态的区间询问,与树状数组有相似之处,但是能用树状数组实现的操作都能用线段树实现。

一般线段树用于以下几种操作:

建树,单点修改,区间查询,区间修改。

首先要进行的就是建树:

void bui(int id,int l,int r)
{if(l==r){tr[id]=a[l];return ;}int mid=(l+r)/2;bui(id*2,l,mid);bui(id*2+1,mid+1,r);tr[id]=max(tr[id*2],tr[id*2+1]);//tr[id]=tr[id*2]+tr[id*2+1];
}//查询最大值与区间和,最小值同理

单点修改:

void gexi(int id,int l,int r,int x,int v)
{if(l==r){tr[id]=v;return ;}int mid=(l+r)/2;if(x<=mid)gexi(id*2,l,mid,x,v);else gexi(id*2+1,mid+1,r,x,v);tr[id]=max(tr[id*2],tr[id*2+1]);//tr[id]=tr[id*2]+tr[id*2+1]
}//查询最大值与区间和

区间查询:

int find(int id,int l,int r,int x,int y)
{if(x<=l&&r<=y){return tr[id];}int mid=(l+r)/2,ans=0;if(x<=mid)ans=max(ans,find(id*2,l,mid,x,y));//ans+=find(id*2,l,mid,x,y);if(y>mid)ans=max(ans,find(id*2+1,mid+1,r,x,y));//ans+=find(id*2+1,mid+1,r,x,y);return ans;
}

区间修改:

void push_up(int id)
{tr[id]=tr[id*2]+tr[id*2+1];
}
void push_down(int id,int l,int r)
{if(lazy[id])//如果有lazy标记 {int mid=(l+r)/2;lazy[id*2]+=lazy[id];//左孩子的lazy加上它的lazy lazy[id*2+1]+=lazy[id];//右孩子的lazy加上它的lazy tr[id*2]+=lazy[id]*(mid-l+1);tr[id*2+1]+=lazy[id]*(r-mid);lazy[id]=0;//清除lazy标记 }
}
void qjgx(int id,int l,int r,int x,int y,int v)
{if(x<=l&&r<=y)//[l,r]被[x,y]包含了 }{lazy[id]+=v;//暂时不下传修改的值,加进lazy标记 tr[id]+=v*(r-l+1); return ;}push_down(id,l,r);//要更新节点了,开始下传修改的值 int mid=(l+r)/2;if(x<=mid)qjgx(id*2,l,mid,x,y,v);//只有x<=mid(即[l,mid]有一部分是被[x,y]覆盖了的)才需要去更新[l,mid]if(y>mid)qjgx(id*2+1,mid+1,r,x,y,v);push_up(id); //子节点更新后父节点也更新 
}

下面是两道例题,可以试着尝试一下这几种操作

一:敌兵布阵

敌人有 N 个工兵营地,编号 1∼N。

初始时,第 i 个营地有 ai 个人。

接下来有若干个命令,命令有 4 种形式:

Add i j,i 和 j 为正整数,表示第 i 个营地增加 j 个人。(j 不超过 30)
Sub i j,i 和 j 为正整数,表示第 i 个营地减少 j 个人。(j 不超过 30)
Query i j,i 和 j 为正整数(i≤j),表示询问第 i 到第 j 个营地的总人数。
End,表示结束,此命令只会作为最后一条命令出现。
请你计算每个 Query 的答案。

输入格式
第一行包含整数 T,表示共有 T 组测试数据。

每组数据第一行包含一个整数 N。

第二行包含 N 个整数 a1,a2,…,aN。

接下来若干行,每行包含一条命令,格式如题目所述。

输出格式
对于第 i 组数据,首先输出一行 Case i:,然后对于每个 Query 询问,输出一行一个整数,表示询问的段中的总人数。

数据范围
1≤T≤10,
1≤N≤50000,
1≤ai≤50,
每组数据最多有 40000 条命令,
保证任何营地的人数都不会减少为负数。

输入样例:

1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End

输出样例:

Case 1:
6
33
59

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define p 50010
int tr[4*p],a[4*p];
void bui(int id,int l,int r)
{if(l==r){tr[id]=a[l];return ;}int mid=(l+r)/2;bui(id*2,l,mid);bui(id*2+1,mid+1,r);tr[id]=tr[id*2]+tr[id*2+1];
}
int find(int id,int l,int r,int x,int y)
{if(x<=l&&r<=y){return tr[id];}int mid=(l+r)/2,ans=0;if(x<=mid)ans+=find(id*2,l,mid,x,y);if(y>mid)ans+=find(id*2+1,mid+1,r,x,y);return ans;
}
void gexi(int id,int l,int r,int x,int v)
{if(l==r){tr[id]+=v;return ;}int mid=(l+r)/2;if(x<=mid)gexi(id*2,l,mid,x,v);else gexi(id*2+1,mid+1,r,x,v);tr[id]=tr[id*2]+tr[id*2+1];
}
int main()
{int t;scanf("%d",&t);for(int k=1;k<=t;k++){int n;scanf("%d",&n);memset(a,0,sizeof(a));memset(tr,0,sizeof(tr));for(int i=1;i<=n;i++)scanf("%d",&a[i]);bui(1,1,n);char x[10];int aa,bb,cc;cout<<"Case "<<k<<":"<<endl;while(~scanf("%s",x)){if(x[0]=='Q'){scanf("%d%d",&aa,&bb);printf("%d\n",find(1,1,n,aa,bb));}else if(x[0]=='A'){scanf("%d%d",&aa,&bb);gexi(1,1,n,aa,bb);}else if(x[0]=='S'){scanf("%d%d",&aa,&bb);gexi(1,1,n,aa,-bb);}elsebreak;}}return 0;
}

二:一个简单的整数问题2

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

C l r d,表示把 A[l],A[l+1],…,A[r] 都加上 d。
Q l r,表示询问数列中第 l∼r 个数的和。
对于每个询问,输出一个整数表示答案。

输入格式
第一行两个整数 N,M。

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

接下来 M 行表示 M 条指令,每条指令的格式如题目描述所示。

输出格式
对于每个询问,输出一个整数表示答案。

每个答案占一行。

数据范围
1≤N,M≤105,
|d|≤10000,
|A[i]|≤109

输入样例:

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

输出样例:

4
55
9
15

AC代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
int sumv[10000001],n,m,a[10000001],lazy[10000001];
void push_up(int id)
{sumv[id] = sumv[id * 2] + sumv[id * 2 + 1];
}
void push_down(int id,int l,int r)
{if(lazy[id]){int mid = (l + r) / 2;lazy[id * 2] += lazy[id];lazy[id * 2 + 1] += lazy[id];sumv[id * 2] += lazy[id] * (mid - l + 1);sumv[id * 2 + 1] += lazy[id] * (r - mid);lazy[id] = 0;}
}
void bui(int id,int l,int r)
{if(l == r){sumv[id] = a[l];return ;}int mid = (l + r) / 2;bui(id * 2,l,mid);bui(id * 2 + 1,mid + 1,r);sumv[id] = sumv[id * 2] + sumv[id * 2 + 1];
}
void qjgx(int id,int l,int r,int x,int y,int v)
{if(l >= x && r <= y){lazy[id] += v;sumv[id] += v * (r - l + 1);return ;}push_down(id,l,r);int mid = (l + r) / 2;if(x <= mid) qjgx(id * 2,l,mid,x,y,v);if(y > mid) qjgx(id * 2 + 1,mid + 1,r,x,y,v);push_up(id);
}
int find(int id,int l,int r,int x,int y)
{if(x <= l && r <= y) return sumv[id];push_down(id,l,r);int mid = (l + r) / 2,ans = 0;if(x <= mid) ans += find(id * 2,l,mid,x,y);if(y > mid) ans += find(id * 2 + 1,mid + 1,r,x,y);return ans;
}
signed main()
{cin>>n>>m;for(int i = 1; i <= n; i++) cin>>a[i];bui(1,1,n);while(m--){string p;int k,x,y;cin>>p>>x>>y;if(p == "C"){cin>>k;qjgx(1,1,n,x,y,k);}else cout<<find(1,1,n,x,y)<<'\n';}return 0;
}

下一篇 codeforces round 885 (div. 2)

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

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

相关文章

VSCode 常用插件集合

目录 一、基础插件二、AI三、Rust插件 一、基础插件 Chinese (Simplified) (简体中文) 此中文&#xff08;简体&#xff09;语言包为 VS Code 提供本地化界面。 Native Debug 本地VSCode调试器。 CodeLLDB 一个由LLDB提供支持的本地调试器。调试c&#xff0c; Rust等编译语言…

【Android实现 资源路径/手机内存/网络文件 下的视频播放】

业务场景&#xff1a;安卓实现播放视频的功能&#xff0c;支持播放不同类型资源下的视频&#xff0c;下面在使用中封装了一个方法&#xff0c;可以根据需要修改调用 一、直接上封装方法 void videoReady(String videoPath ,String videoType){switch (videoType) {case "…

使用ffmpeg合并视频遇到的坑

下面以Linux环境介绍为主 1.ffmpeg可执行命令不同的环境是不同的&#xff0c;Linux在执行命令前还需要授权。 2.合并视频命令&#xff1a; 主要命令: {} -f concat -auto_convert 0 -safe 0 -i {} -y -c:v copy 坑一&#xff1a;其中第一个花括号替换的是可执行命令所在的…

【GitOps系列】使用Kustomize和Helm定义应用配置

文章目录 使用 Kustomize 定义应用改造示例应用1.创建基准和多环境目录2.环境差异分析3.为 Base 目录创建通用 Manifest4.为开发环境目录创建差异 Manifest5.为预发布环境创建差异 Manifest6.为生产环境创建差异 Manifest 部署 Kustomize 应用部署到开发环境部署到生产环境 使用…

c++ 的引用

c 引用 引用的概念 应用不是重新去定义一个变量&#xff0c;而是给变量取别名。 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空 间&#xff0c;它和它引用的变量共用同一块内存空间 比如&#xff1a; int a…

OpenCv (C++) 使用矩形 Rect 覆盖图像中某个区域

文章目录 1. 使用矩形将图像中某个区域置为黑色2. cv::Rect 类介绍 1. 使用矩形将图像中某个区域置为黑色 推荐参考博客&#xff1a;OpenCV实现将任意形状ROI区域置黑&#xff08;多边形区域置黑&#xff09; 比较常用的是使用 Rect 矩形实现该功能&#xff0c;代码如下&…

打造i-SMART智能网联平台,亚马逊云科技助力上汽快速出海

当前在各大外资车企不断加码在华投资之际&#xff0c;越来越多的中国汽车品牌纷纷开始走出国门&#xff0c;加速推进全球化业务&#xff0c;将赛道转至更为广阔的海外市场。 上汽海外出行科技有限公司&#xff08;简称“上汽海外出行”&#xff09;成立于2018年&#xff0c;承…

linux高并发web服务器开发(web服务器)18_函数解析http请求, 正则表达式,sscanf使用,http中数据特殊字符编码解码

pdf详情版 01 学习目标 编写函数解析http请求 ○ GET /hello.html HTTP/1.1\r\n ○ 将上述字符串分为三部分解析出来编写函数根据文件后缀&#xff0c;返回对应的文件类型sscanf - 读取格式化的字符串中的数据 ○ 使用正则表达式拆分 ○ [^ ]的用法通过浏览器请求目录数据 ○…

【unity之IMGUI实践】单例模式管理数据存储【二】

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

每日一题——迷宫问题(I)

迷宫问题——I 题目链接 思路 创建二维数组&#xff0c;并实现输入 首先输入二维数组的行和列&#xff1a; int n, m; scanf("%d%d", &n, &m);然后动态开辟二维数组&#xff1a; 注&#xff1a;对动态开辟还不太了解的同学可以看看&#x1f449;C语言—…

CPU密集型和IO密集型任务的权衡:如何找到最佳平衡点

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、CPU密集型与IO密集型3.1、CPU密集型3.2、I/O密…

opencv-15 数字水印原理

最低有效位&#xff08;Least Significant Bit&#xff0c;LSB&#xff09;指的是一个二进制数中的第 0 位&#xff08;即最低位&#xff09;。 最低有效位信息隐藏指的是&#xff0c;将一个需要隐藏的二值图像信息嵌入载体图像的最低有效位&#xff0c;即将载体图像的最低有效…

再开源一款轻量内存池

前两天已开源线程池&#xff0c;开源一款轻量线程池项目&#xff0c;本节继续开源另一个孪生兄弟&#xff1a;内存池。 本节的线程池与内存池代码解析会在我的星球详细讲解。 内存池&#xff1a;https://github.com/Light-City/light-memory-pool 线程池&#xff1a;https://gi…

Python案例分析|使用Python图像处理库Pillow处理图像文件

本案例通过使用Python图像处理库Pillow&#xff0c;帮助大家进一步了解Python的基本概念&#xff1a;模块、对象、方法和函数的使用 使用Python语言解决实际问题时&#xff0c;往往需要使用由第三方开发的开源Python软件库。 本案例使用图像处理库Pillow中的模块、对象来处理…

Java设计模式-单例模式

单例模式 1.单例模式含义 单例模式就是保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。 其实单例模式很好理解&#xff0c;当我们new一个对象实例的时候&#xff0c;这个对象会被放到一个内存中&#xff0c;当我们再次new同一个对象的实例的时候&#xf…

ES6模块化与异步编程高级用法

目录 ES6 模块化 1、什么是 ES6 模块化规范 2、在 node.js 中体验 ES6 模块化 3、ES6 模块化的基本语法 Promise 1. 回调地狱 2、Promise 的基本概念 3、基于回调函数按顺序读取文件内容 4.、基于 then-fs 读取文件内容 4.1 then-fs 的基本使用 4.2 .then() 方法的特…

ZooKeeper原理剖析

1.ZooKeeper简介 ZooKeeper是一个分布式、高可用性的协调服务。在大数据产品中主要提供两个功能&#xff1a; 帮助系统避免单点故障&#xff0c;建立可靠的应用程序。提供分布式协作服务和维护配置信息。 2.ZooKeeper结构 ZooKeeper集群中的节点分为三种角色&#xff1a;Le…

SSH客户端连接远程服务器

目录 一、什么是客户端连接远程服务器 二、什么是服务端连接远程服务器 三、查看网络信息 1、图形程序查看网络信息 2、命令查看网络信息 四、SSH客户端&#xff08;Linux&#xff09; 五、SSH客户端&#xff08;windows&#xff09; 六、SSH远程服务器 一、什么是客户…

75、简述你对RPC、RMI的理解

简述你对RPC、RMI的理解 RPC&#xff1a;在本地调用远程的函数&#xff0c;远程过程调用&#xff0c;可以跨语言实现 httpClient RMI&#xff1a;远程方法调用&#xff0c;java中用于实现RPC的一种机制&#xff0c;RPC的java版本&#xff0c;是J2EE的网络调用机制&#xff0c…

git如何撤销commit(未push)

文章目录 前言undo commitreset current branch to here Undo Commit&#xff0c;Revert Commit&#xff0c;Drop Commit的区别 是否删除对代码的修改是否删除Commit记录是否会新增Commit记录Undo Commit不会未Push会&#xff0c;已Push不会不会Revert Commit会不会会Drop Com…