浅谈线段树

来源:互联网 发布:数据库查询语句讲解 编辑:程序博客网 时间:2024/06/07 16:34

-————终于从数论中爬出来了,没有继续写数论了
点修改
例题:给出一个有n个元素的数组a1,a2,a3,….an,设计一个数据结构,来支持修改某个元素和计算某个区间的最值
分析:因为要修改元素并且要计算最值,就不能再用ST表和遍历整个区间来计算,这两种方法的时间复杂度都较高,且如果一边修改元素,一边找最值,写出的代码就可以直接拿去卡死评测机.
所以我们要引入线段树(又名区间树)这个新的数据结构,而上述的两种问题的解决恰恰是线段树最优美的地方.
这里写图片描述
如图所示将n个元素由各个结点来储存,如在[5,7]中就可以储存5,6,7之中的最值.而如果要把7这个结点的值修改,则需要把结点[5,7],[1,7],[1,13]这三个结点的值修改.相比起将数组全部遍历,这种方法简单而高效啊.

#include<cstdio>using namespace std;int n;  int a[100100];  int minv[101000];int minx(int xxx,int yyy){    if(xxx<yyy)  return xxx;    else  return yyy;}void init(){    scanf("%d",&n);    for(int i=1;i<=n;++i){       scanf("%d",&a[i]);    }}void hebin(int k){    minv[k]=minx(minv[k<<1],minv[k<<1|1]);}void jianshu(int ql,int qr,int o){    if(ql==qr){        minv[o]=a[ql];        return;    }    int m=ql+(qr-ql)/2;    jianshu(ql,m,o<<1);    jianshu(m+1,qr,o<<1|1);    hebin(o);}int main(){    init();    jianshu(1,8,1);    return 0;}

这是建树的代码,个人比较喜欢用递归实现(像不像快速排序)
下面是先是查询的代码,然后是更新的代码

int ql,qr; //全局变量(查询ql,q2中的最值),这里展示的是最小值 int lookup(int o,int l,int r){  //o表示当前结点编号     int m=l+(r-l)/2,ans=INF;    //m这样写是一个小技巧,防止超int(尽量养成这个好习惯)     if(ql<=l && r<=qr)  return minv[o];    if(ql<=m)  ans=minx(ans,lookup(o*2,ql,m));    if(m<qr)  ans=minx(ans,lookup(o*2+1,m+1,qr));    return ans;}

int p,v;//将a[p]修改为v
void update(int o,int ql,int qr)
{
int m=ql+(qr-ql)/2;
if(ql==qr) minv[o]=v;
else
{
if(p<=m) update(o*2,ql,m);
else update(o*2+1,m+1,qr);
minv[o]=minx(minv[o*2],minv[o*2+1]);
}
}