C++ 线段树—模板&总结
在信息学竞赛中,经常遇到这样一类问题:这类问题通常可以建模成数轴上的问题或是数列的问题,具体的操作一般是每次对数轴上的一个区间或是数列中的连续若干个数进行一种相同的处理。常规的做法一般依托于线性表这种数据结构,导致了处理只能针对各个元素逐个进行,因此算法的效率较低。
线段树是一种能够有效处理区间操作的高级数据结构,利用这种数据结构,我们能够设计出针对上述问题更加高效的算法。
线段树的题目通常比较明显,一般一个很明显的特征是m次对某一区间长度的查询。或者是修改。所以我们通常需要的只是将线段树的模型稍加修改,进而套入题目中即可。
模板:
对单个点的修改,和对一段区间的查询:
//线段树单个点修改&区间查询
#include<iostream>
#include<iomanip>
#include<cstring>
#include<climits>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<vector>
#include<map>
#include<algorithm>
#include<string>
#include<memory>
using namespace std; const int e=100006;
struct qq
{
int maxx;
}tree[4*e];//线段树要开4倍的点的个数
int n,t,a,b; void updata(int l,int r,int root)
{
if(r<a || l>a) return;
if(r==l)
{
tree[root].maxx=b;
return;
} int mid=(l+r)/2;
updata(l,mid,root*2);
updata(mid+1,r,root*2+1);
tree[root].maxx=max(tree[root*2].maxx,tree[root*2+1].maxx);
} int search(int l,int r,int root)
{
if(l>b || r<a) return(-999999999); if(l>=a && r<=b) return(tree[root].maxx); int mid=(l+r)/2;
return(max( search(l,mid,root*2), search(mid+1,r,root*2+1)));
} int main()
{
memset(tree,0,sizeof(tree));
cin>>n; for(int i=0;i<n;i++)
{
scanf("%d%d%d",&t,&a,&b); if(t==1) updata(1,n,1);//将点a的值改为b
if(t==2) cout<< search(1,n,1) << endl;//查找区间a(含)到b(含)的最大值;
} return 0;
}
对一段区间的修改和查询:
//线段树 区间 修改&查询
#include<iostream>
#include<iomanip>
#include<cstring>
#include<climits>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<vector>
#include<map>
#include<algorithm>
#include<string>
#include<memory>
using namespace std; const int e=100006;
struct qq
{
int maxx,delta;
}tree[4*e];//线段树要开4倍的点的个数
int n,t,a,b; void updata(int l,int r,int root)//更新数据
{
if(b<l || r<a) return; if(l>=a && r<=b)//这句是核心,若当前区间包含于修改区间,就不往下传,(未传到叶子节点);
{
tree[root].maxx++;
tree[root].delta++;
return;
} int mid=(l+r)/2,delta=tree[root].delta;
tree[root*2].maxx+=delta;
tree[root*2].delta+=delta;
tree[root*2+1].maxx+=delta;
tree[root*2+1].delta+=delta;
tree[root].delta=0;//这句很关键,根的偏移量传递到子树后清零
updata(l,mid,root*2);
updata(mid+1,r,root*2+1);
tree[root].maxx=max( tree[root*2].maxx, tree[root*2+1].maxx);
return;
} int search(int l,int r,int root)
{
if(l>b || r<a) return(-99999999); if(l>=a && r<=b) return(tree[root].maxx); int mid=(l+r)/2,delta=tree[root].delta;
tree[root*2].maxx+=delta;
tree[root*2].delta+=delta;
tree[root*2+1].maxx+=delta;
tree[root*2+1].delta+=delta;
tree[root].delta=0; //这句很关键,根的偏移量传递到子树后清零
return(max( search(l,mid,root*2), search(mid+1,r,root*2+1)));
} int main()
{
memset(tree,0,sizeof(tree));
cin>>n; for(int i=0;i<n;i++)
{
scanf("%d%d%d",&t,&a,&b); if(t==1) updata(1,n,1);
if(t==2) cout<< search(1,n,1) << endl;
} return 0;
}
以下是做线段树题目时的易错点:
1、开线段树的结构体时一定要开到4倍的点的大小;
2、写区间求和时的题目时search()函数的返回值在不再区间里时返回0,而区间求最小值时返999999999,最大值时返回-999999999;(int时)一定要是九个9,不然有些极限数据会卡范围;
3、写修改单个点的值和一个区间的值的函数最好分开,一个是节省时间,还有可以防止代码混乱而出错;
4、Search()&updata()函数中判断区间范围的if语句中l,r和查找的区间a,b的关系容易出错;
5、注意根节点和子节点的关系,特别是+1的问题,归结为一句话就是:若加都加,若不加都不加即:mid=(l+r);左子树:l~mid(不加一),根为root*2;右子树:r~mid+1(加一了),根为root*2+1(也加一);
6、权值是在边上还是点上,这两种关系代码判断上有不同;
7、结构体赋初值的时候也要注意,根据所求的是最大还是最小还是和来判断;
8、线段树的左端点在数组中的下标一定要是1,而不是0。
C++ 线段树—模板&总结的更多相关文章
- [AHOI 2009] 维护序列(线段树模板题)
1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小 ...
- hdu1754 I hate it线段树模板 区间最值查询
题目链接:这道题是线段树,树状数组最基础的问题 两种分类方式:按照更新对象和查询对象 单点更新,区间查询; 区间更新,单点查询; 按照整体维护的对象: 维护前缀和; 维护区间最值. 线段树模板代码 # ...
- P3373 线段树模板
好,这是一个线段树模板. #include <cstdio> using namespace std; ; long long int sum[N],tag1[N],tag2[N],mo; ...
- 线段树模板hdu 1754:I Hate It
I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- UESTC - 1057 秋实大哥与花 线段树模板题
http://acm.uestc.edu.cn/#/problem/show/1057 题意:给你n个数,q次操作,每次在l,r上加上x并输出此区间的sum 题解:线段树模板, #define _CR ...
- POJ 3468 A Simple Problem with Integers(线段树模板之区间增减更新 区间求和查询)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 140120 ...
- hdu 4819 二维线段树模板
/* HDU 4819 Mosaic 题意:查询某个矩形内的最大最小值, 修改矩形内某点的值为该矩形(Mi+MA)/2; 二维线段树模板: 区间最值,单点更新. */ #include<bits ...
- POJ3468:A Simple Problem with Integers(线段树模板)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 149972 ...
- HDU1166:敌兵布阵(线段树模板)
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- hdu1823(二维线段树模板题)
hdu1823 题意 单点更新,求二维区间最值. 分析 二维线段树模板题. 二维线段树实际上就是树套树,即每个结点都要再建一颗线段树,维护对应的信息. 一般一维线段树是切割某一可变区间直到满足所要查询 ...
随机推荐
- C++ Primer 笔记——类
1.定义在类内部的函数是隐式的inline函数. 2.因为this的目的总是指向“这个”对象,所以this是一个常量指针,我们不允许改变this中保存的地址. 3.常量成员函数:允许把const关键字 ...
- python 内置数据类型之数字
目录: 1.2. 数字 1.2.1. 数字类型 1.2.2. 浮点数 1.2.3. 进制记数 1.2.4. 设置小数精度 1.2.5. 分数 1.2.6. 除法 1.2 数字 1.2.1 数字类型 ...
- 51Nod 1298 圆与三角形(计算几何)
1298 圆与三角形 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 给出圆的圆心和半径,以及三角形的三个顶点,问圆同三角形是否相交.相交输出"Yes&quo ...
- 据说是Flord算法
贵有恒,何必三更起五更眠:最无益,莫过一日曝十日寒. 问题 C: Restoring Road Network 问题 C: Restoring Road Network 时间限制: 1 Sec 内存 ...
- .Net分布式锁
项目中一般使用lock作为锁,以便于多线程操作确保库内数据统一.但是如果分布式部署项目,则这种锁就是去了意义,这时可以使用redis或memcache的add方法作为分布式锁. 栗子
- Visual Studio中的.suo(Solution User Options)文件
其实关于.suo文件,官方文档和网上很多资料就说明的十分详细了,本文主要按照我自己的理解将其整理归纳成一篇笔记以备日后查看..suo文件全称为:Solution User Options,看了很多资料 ...
- ASP.NET CORE Swagger
Package 添加并配置Swagger中间件 将Swagger生成器添加到方法中的服务集合中Startup.ConfigureServices: public void ConfigureServi ...
- photoshop CC智能切图
网页设计在技术层面上,第一步是美工做出网页效果图,第二步就是网页前端进行网页切图.网页切图工具常用的有fireworks.PS,这里使用PS进行网页切图. 我们通过设计稿,得到我们想要的产出物(如.p ...
- linux改权限
改变文件夹本身权限,不改动子文件(夹) chmod 600 my/ 改变文件夹及子目录下所有文件(夹)权限 chmod -R 777 my/ 统一修改 cd my 修改文件夹权限为755 find - ...
- update + join 多表操作
UPDATE vtiger_notificationcf as a INNER JOIN vtiger_crmentity as b ON a.notificationid = b.crmid SET ...