在信息学竞赛中,经常遇到这样一类问题:这类问题通常可以建模成数轴上的问题或是数列的问题,具体的操作一般是每次对数轴上的一个区间或是数列中的连续若干个数进行一种相同的处理。常规的做法一般依托于线性表这种数据结构,导致了处理只能针对各个元素逐个进行,因此算法的效率较低。

线段树是一种能够有效处理区间操作的高级数据结构,利用这种数据结构,我们能够设计出针对上述问题更加高效的算法。

线段树的题目通常比较明显,一般一个很明显的特征是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++ 线段树—模板&总结的更多相关文章

  1. [AHOI 2009] 维护序列(线段树模板题)

    1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小 ...

  2. hdu1754 I hate it线段树模板 区间最值查询

    题目链接:这道题是线段树,树状数组最基础的问题 两种分类方式:按照更新对象和查询对象 单点更新,区间查询; 区间更新,单点查询; 按照整体维护的对象: 维护前缀和; 维护区间最值. 线段树模板代码 # ...

  3. P3373 线段树模板

    好,这是一个线段树模板. #include <cstdio> using namespace std; ; long long int sum[N],tag1[N],tag2[N],mo; ...

  4. 线段树模板hdu 1754:I Hate It

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  5. UESTC - 1057 秋实大哥与花 线段树模板题

    http://acm.uestc.edu.cn/#/problem/show/1057 题意:给你n个数,q次操作,每次在l,r上加上x并输出此区间的sum 题解:线段树模板, #define _CR ...

  6. POJ 3468 A Simple Problem with Integers(线段树模板之区间增减更新 区间求和查询)

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 140120 ...

  7. hdu 4819 二维线段树模板

    /* HDU 4819 Mosaic 题意:查询某个矩形内的最大最小值, 修改矩形内某点的值为该矩形(Mi+MA)/2; 二维线段树模板: 区间最值,单点更新. */ #include<bits ...

  8. POJ3468:A Simple Problem with Integers(线段树模板)

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 149972 ...

  9. HDU1166:敌兵布阵(线段树模板)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  10. hdu1823(二维线段树模板题)

    hdu1823 题意 单点更新,求二维区间最值. 分析 二维线段树模板题. 二维线段树实际上就是树套树,即每个结点都要再建一颗线段树,维护对应的信息. 一般一维线段树是切割某一可变区间直到满足所要查询 ...

随机推荐

  1. Appium Desired Capabilities

    Appium Desired Capabilities Desired Capabilities 是由 keys 和 values 组成的 JSON 对象. 举个简单例子: { "platf ...

  2. python SSL处理

    浏览器SSL提示 我们看一下IE的解决方案,对ie浏览器而言,需要添加Desired Capabilities的acceptSslCerts选项为True,代码如下: 的 112 / 166 #_*_ ...

  3. 如何录制Chrome或者Linux下的应用

    说明: PortMapping的这种用法其实早就有了,开始我一直没注意到这点,后面才发现了这个功能,特别在<性能测试进阶指南Loadrunner11实战>第二版中更新. 不是所有的对象都能 ...

  4. 饮冰三年-人工智能-linux-03 Linux文件管理(权限管理+归档+压缩)

    1:对文件的权限管理 drwxr-xr-x. 最后一个.表示在安全情况下创建的.selinux a: d表示目录:-表示普通文件:l表示快捷方式:b设备文件 b:- 属主的权限 r:读权限:w:写权限 ...

  5. 集腋成裘-02-css基础-01

    CSS 层叠样式表(Cascading Style Sheets)(级联样式表) 1 选择器 1.1 写法 选择器是一个选择标签的过程. 选择器{属性:值;...} 1.2 基础选择器 标签选择器 类 ...

  6. 目标检测算法之YOLOv1与v2

    YOLO:You Only Look Once(只需看一眼) 基于深度学习方法的一个特点就是实现端到端的检测,相对于其他目标检测与识别方法(如Fast R-CNN)将目标识别任务分成目标区域预测和类别 ...

  7. WARN conf.FlumeConfiguration: Could not configure sink sink1 due to: No channel configured for sink: sink1 org.apache.flume.conf.ConfigurationException: No channel configured for sink: sink1

    1.错误如下所示,启动flume采集文件到hdfs案例的时候,出现如下所示的错误: 大概是说No channel configured for sink,所以应该是sink哪里配置出现了错误,百度了一 ...

  8. [转] whistle--全新的跨平台web调试工具

    whistle是基于Node实现的跨平台web调试代理工具,类似的工具有Windows平台上的Fiddler+Willow,基于Java实现的Charles,及公司同事基于Node实现的Livepoo ...

  9. ionic2程序调试

    新手一枚,之前一直做.net开发,最近接触Ionic2,也没有人带,只能自己一点点抠文档,查资料.一直苦于无法直接调试打包发不好的app,只能在代码里面加上alert一点一点的抛出要看信息,感觉就像瞎 ...

  10. redis中实现redis-cli任意目录执行