首页 > 其他 > 详细

线段树模板

时间:2015-03-26 01:24:59      阅读:270      评论:0      收藏:0      [点我收藏+]

下面的两份线段树模板,一份是单点更新维护区间最小值,一份是区间更新,同时维护区间和,区间最大最小值。

代码如下:

///线段树单点更新
#include<iostream>
#include<cstdio>
#include<cstring>
#include<fstream>
using namespace std;

#define maxn 1000
#define INF 0x3f3f3f3f

int a[maxn];
int minv[maxn*4];   ///线段树标记数组

///线段树构造函数
///其实就是要找到相应线段在线段树中的编号
///然后记录一下信息(形参表示编号为o的线段树节点对应的线段是L--R)
void build(int o,int L,int R)
{
    int M=L+(R-L)/2;
    if(L==R)
        minv[o]=a[L];
    else
    {
        build(2*o,L,M);
        build(2*o+1,M+1,R);
        minv[o]=min(minv[2*o],minv[2*o+1]);
    }
}

///单点更新 更新a[p]的值为v
///先找到这个点在线段树中对应的编号,更新
///然后再递归向上更新
void update(int o,int L,int R,int p,int v)
{
    int M=L+(R-L)/2;
    if(L==R)
        minv[o]=v;
    else
    {
        if(p<=M)
            update(o*2,L,M,p,v);
        else
            update(o*2+1,M+1,R,p,v);
        minv[o]=min(minv[2*o],minv[2*o+1]);
    }
}

///区间查询 查询区间ql,qr之间的最小值
int query(int o,int L,int R,int ql,int qr)
{
    int ans=INF; int M=L+(R-L)/2;
    ///当前区间完全被待查询区间包含
    if(ql<=L&&qr>=R)
        return minv[o];
    if(ql<=M)  ///查询区间与左区间有交点
        ans=min(ans,query(o*2,L,M,ql,qr));
    if(qr>M)  ///查询区间与右区间有交点
        ans=min(ans,query(2*o+1,M+1,R,ql,qr));
    return ans;
}

int main()
{
    int n;
    ifstream fin("lkl.txt");
    while(fin>>n)
    {
        for(int i=1;i<=n;i++)
           fin>>a[i];
        build(1,1,n);
        cout<<query(1,1,n,2,5)<<endl;  ///查询a[1,n]中的最小值
        update(1,1,n,3,-1);   ///修改a[3]=-1
        cout<<query(1,1,n,2,5)<<endl; ///查询a[1,n]中的最小值
    }
  return 0;
}
///线段树区间更新加维护 区间最大值 最小值 区间和
#include<iostream>
#include<cstdio>
#include<cstring>
#include<fstream>
using namespace std;

#define INF 0x3f3f3f3f
#define maxn 1000

int a[maxn],sum[maxn*4],minv[maxn*4];
///每个节点都会被附加一个lazy标记
int lazy[maxn*4],maxv[maxn*4];

///更新子节点后维护父节点信息
void maintain(int o,int L,int R)
{
    int lc=2*o,rc=2*o+1;
    sum[o]=sum[lc]+sum[rc];
    minv[o]=min(minv[lc],minv[rc]);
    maxv[o]=max(maxv[lc],maxv[rc]);
}

///递归查询或者修改时向下传递信息
void pushdown(int o,int L,int R)
{
    int lc=2*o,rc=2*o+1,M=(L+R)/2;
    ///如果当前父节点有lazy标记的话就传递给它的儿子节点
    if(lazy[o]!=INF)
    {
        sum[lc]+=lazy[o]*(M-L+1);
        sum[rc]+=lazy[o]*(R-M);
        minv[lc]+=lazy[o];
        maxv[lc]+=lazy[o];
        minv[rc]+=lazy[o];
        maxv[rc]+=lazy[o];
        if(lazy[2*o]==INF)
            lazy[2*o]=lazy[o];
        else
            lazy[2*o]+=lazy[o];
        if(lazy[2*o+1]==INF)
            lazy[2*0+1]=lazy[o];
        else
            lazy[2*o+1]+=lazy[o];
        lazy[o]=INF;   ///传递完成后就将父节点的标记清除
    }
}

void build(int o,int L,int R)
{
     int M=L+(R-L)/2;
     if(L==R)
     {
         sum[o]=a[L];
         minv[o]=a[L];
         maxv[o]=a[L];
     }
     else
     {
         build(2*o,L,M);
         build(2*o+1,M+1,R);
         maintain(o,L,R);
     }
}

void update(int o,int L,int R,int ql,int qr,int add)
{
    int M=L+(R-L)/2;
    if(ql<=L&&qr>=R)
    {
        sum[o]+=(R-L+1)*add;
        minv[o]+=add;
        maxv[o]+=add;
        if(lazy[o]==INF)
            lazy[o]=add;
        else
            lazy[o]+=add;
        return ;
    }
    pushdown(o,L,R);
    if(ql<=M)
        update(o*2,L,M,ql,qr,add);
    if(qr>M)
        update(2*o+1,M+1,R,ql,qr,add);
    maintain(o,L,R);
}
///定义全局变量用来记录当前区间查询的结果
int _max,_min,_sum;
void query(int o,int L,int R,int ql,int qr)
{
    int M=L+(R-L)/2;
    if(ql<=L&&qr>=R)
    {
        _sum+=sum[o];
        _max=max(_max,maxv[o]);
        _min=min(_min,minv[o]);
        return ;
    }
    pushdown(o,L,R);
    if(ql<=M)
        query(2*o,L,M,ql,qr);
    if(qr>M)
        query(2*o+1,M+1,R,ql,qr);
}

void Init()
{
     _max=0,_min=INF,_sum=0;
}

void print(int x,int y)
{
    cout<<x<<" "<<y<<endl;
    cout<<_max<<" "<<_min<<" "<<_sum<<endl;
}

int main()
{
    int n;
    ifstream fin("lkl.txt");
    while(fin>>n)
    {
        memset(lazy,0x3f,sizeof(lazy));
        for(int i=1;i<=n;i++)
           fin>>a[i];
        build(1,1,n);
        Init();
        query(1,1,n,1,1);  ///查询a[1,n]中的最小值,最大值,区间和
        print(2,5);
        update(1,1,n,2,2,-1);   ///a[2,5]中的所有元素都减1
        Init();
        query(1,1,n,2,2); ///查询a[2,5]中的最小值,最大值,区间和
        print(2,5);
        Init();
        update(1,1,n,4,4,4); ///查询a[2,5]中的最小值,最大值,区间和
        query(1,1,n,4,4);
        print(2,5);
    }
 return 0;
}

线段树模板

原文:http://blog.csdn.net/acm_lkl/article/details/44631807

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!